
日志框架
日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用
在计算机中,日志文件是记录在操作系统或其他软件运行中发生的事件或在通信软件的不同用户之间的消息的文件。记录是保持日志的行为。在最简单的情况下,消息被写入单个日志文件
日志的作用
在Java项目调试时,查看栈信息可以方便地知道当前程序的运行状态,输出的日志便于记录程序在之前的运行结果。如果你大量使用System.out或者System.err,这是一种最方便最有效的方法,但显得不够专业
不要以为项目能正确跑起来就可以高枕无忧,项目在运行一段时候后,可能由于数据问题,网络问题,内存问题等出现异常。这时日志可以帮助开发或者运维人员快速定位错误位置,提出解决方案
大数据的兴起,使得大量的日志分析成为可能,ELK也让日志分析门槛降低了很多。日志中蕴含了大量的用户数据,包括点击行为,兴趣偏好等,用户画像对于公司下一步的战略方向有一定指引作用
最常见的普通日志
主流的日志框架
日志实现(具体干活的):JUL(java util logging)、logback、log4j、log4j2
日志门面(指定规则的):JCL(Jakarta Commons Logging)、slf4j( Simple Logging Facade for Java)
JUL 日志框架
JUL全称Java util Logging是java原生的日志框架,使用时不需要另外引用第三方类库,相对其他日志框 架使用方便,学习简单,能够在小型应用中灵活使用
Loggers 被称为记录器,应用程序通过获取Logger对象,调用其API来发布日志信息。Logger 通常时应用程序访问日志系统的入口程序
Appenders 也被称为Handlers,每个Logger都会关联一组Handlers,Logger会将日志交给关联 Handlers处理,由Handlers负责将日志做记录。Handlers在此是一个抽象,其具体的实现决定了 日志记录的位置可以是控制台、文件、网络上的其他日志服务或操作系统日志等
Layouts 也被称为Formatters,它负责对日志事件中的数据进行转换和格式化。Layouts决定了 数据在一条日志记录中的最终形式
Level 每条日志消息都有一个关联的日志级别。该级别粗略指导了日志消息的重要性和紧迫,我 可以将Level和Loggers,Appenders做关联以便于我们过滤消息
Filters 过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过
总结
用户使用Logger来进行日志记录,Logger持有若干个Handler,日志的输出操作是由Handler完成的。 在Handler在输出日志前,会经过Filter的过滤,判断哪些日志级别过滤放行哪些拦截,Handler会将日志内容输出到指定位置(日志文件、控制台等)。Handler在输出日志时会使用Layout,将输出内容进行排版
日志的级别
jul中定义的日志级别,从上述例子中我们也看到使用info和warning打印出的日志有不同的前缀,通过给日志设置不同的级别可以清晰的从日志中区分出哪些是基本信息,哪些是调试信息,哪些是严重的异常
- java.util.logging.Level中定义了日志的级别
 
server 最高值
warning 
info 默认级别
config
fine
finer
finest 最低值
OFF 可用来关闭日志记录
ALL 启用所有消息的日志记录
Logger之间的父子关系

JUL中Logger之间存在父子关系,这种父子关系通过树状结构存储,JUL在初始化时会创建一个顶层 RootLogger作为所有Logger父Logger,存储上作为树状结构的根节点。并父子关系通过名称来关联。默认子Logger会继承父Logger的属性
常用的转换符
| 转换符 | 
详细说明 | 
| %s | 
字符串类型 | 
| %c | 
字符类型 | 
| %b | 
布尔类型 | 
| %d(十进制) | 
整数类型 | 
| %x(十六进制) | 
整数类型(十六进制) | 
| %o | 
整数类型(八进制) | 
| %f | 
浮点类型 | 
| %a | 
十六进制浮点类型 | 
| %e | 
指数类型 | 
| %n | 
换行符 | 
| %tx | 
日期与时间类型(x代表不同的日期与时间转换符) | 
特殊符号
| 标志 | 
说明 | 
示例 | 
结果 | 
| + | 
为正数或者负数添加符号,因为一般整数不会主动加符号 | 
(“%+d”,15) | 
+15 | 
| 0 | 
数字前面补0,用于对齐 | 
(“%04d”, 99) | 
0099 | 
| 空格 | 
在整数之前添加指定数量的空格 | 
(“%4d”, 99) | 
99 | 
| , | 
以“,”对数字分组(常用显示金额) | 
(“%,f”, 9999.99) | 
9,999.990000 | 
| ( | 
使用括号包含负数 | 
(“%(f”, -99.99) | 
(99.990000) | 
日期处理
| 标志 | 
说明 | 
示例 | 
| c | 
包括全部日期和时间信息 | 
周四 10月 21 14:52:10 GMT+08:00 2021 | 
| F | 
年-月-日”格式 | 
2021-10-21 | 
| D | 
月/日/年”格式 | 
10/21/21 | 
| r | 
HH:MM:SS PM”格式(12时制) | 
02:53:20 下午 | 
| T | 
HH:MM:SS”格式(24时制) | 
14:53:39 | 
| R | 
HH:MM”格式(24时制) | 
14:53 | 
| b | 
月份本地化 | 
0月 | 
| y | 
两位的年 | 
21 | 
| Y | 
四位的年 | 
2021 | 
| m | 
月 | 
10 | 
| d | 
日 | 
21 | 
| H | 
24小时制的时 | 
14 | 
| I | 
12小时制的时 | 
2 | 
| M | 
分 | 
57 | 
| S | 
秒 | 
46 | 
| s | 
秒为单位的时间戳 | 
1634799527 | 
| p | 
上午还是下午 | 
下午 | 
JUL配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
   | public class JULTest {
      static{                  LogManager logManager = LogManager.getLogManager();
                   InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("logger.properties");
          try {
              logManager.readConfiguration(inputStream);         } catch (IOException e) {             e.printStackTrace();         }     }
      public static final Logger LOGGER = Logger.getLogger(JULTest.class.getName());
      @Test     public void testJuc() throws IOException {
                   LOGGER.setUseParentHandlers(false);
                   ConsoleHandler consoleHandler = new ConsoleHandler();         consoleHandler.setFormatter(new SimpleFormatter());                  consoleHandler.setLevel(Level.ALL);
                   FileHandler fileHandler = new FileHandler("D:/logs/JULTest.log",true);         fileHandler.setFormatter(new SimpleFormatter());         fileHandler.setLevel(Level.ALL);
                   LOGGER.addHandler(consoleHandler);
          LOGGER.addHandler(fileHandler);
                   LOGGER.setLevel(Level.ALL);
          LOGGER.severe("server: 严重");
          LOGGER.warning("warning: 警告");
          LOGGER.info("info: 信息");
          LOGGER.fine("fine: JUL无显示 因为Leve 低于 info JDK默认级别配置的是info及info以上");
          LOGGER.finer("finer: JUL无显示 因为Leve 低于 info JDK默认级别配置的是info及info以上");
          LOGGER.finest("finest: JUL无显示 因为Leve 低于 info JDK默认级别配置的是info及info以上");
      }
      @Test     public void testParent(){
                   Logger logger = Logger.getLogger(JULTest.class.getName());
 
 
 
 
 
 
 
                   Logger logger1 = Logger.getLogger("com.dream");
                   logger1.setUseParentHandlers(false);
                   ConsoleHandler consoleHandler = new ConsoleHandler();
                   consoleHandler.setFormatter(new SimpleFormatter());
                   consoleHandler.setLevel(Level.ALL);
                   logger1.addHandler(consoleHandler);
                   logger1.setLevel(Level.ALL);
          logger.info("info");
          logger.fine("fine");
 
 
 
 
      }
      @Test     public void readConfig() throws IOException {
          Logger logger = Logger.getLogger(JULTest.class.getName());
          logger.warning("warning");         logger.finer("finer");         logger.fine("fine");
          try{             Integer result = 1 / 0;         }catch (Exception e){             logger.throwing(JULTest.class.getName(),"readConfig",e);         }     } }
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   |  handlers= java.util.logging.ConsoleHandler .level= FINE
  com.dream.xiaobo.handlers = java.util.logging.ConsoleHandler,java.util.logging.FileHandler com.dream.xiaobo.level = FINER
  com.dream.xiaobo.useParentHandlers = false
 
  java.util.logging.FileHandler.pattern = D:/logs/java%u.log java.util.logging.FileHandler.limit = 50000 java.util.logging.FileHandler.append=true java.util.logging.FileHandler.count = 1 java.util.logging.FileHandler.maxLocks = 100 java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter java.util.logging.FileHandler.level = FINER java.util.logging.ConsoleHandler.level = FINER
  java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
 
  | 
 
Log4j 日志框架
Log4j是Apache下的一款开源的日志框架
简单演示
1 2 3 4 5
   | <dependency>     <groupId>log4j</groupId>     <artifactId>log4j</artifactId>     <version>1.2.13</version> </dependency>
   | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | public static final Logger LOGGER = Logger.getLogger(Log4jTest.class);
      @Test     public void testLog4j(){
                   BasicConfigurator.configure();
                   LOGGER.info("hello log4j");                  LOGGER.fatal("fatal");          LOGGER.error("error");          LOGGER.warn("warn");          LOGGER.info("info");          LOGGER.debug("debug");          LOGGER.trace("trace");      }
   | 
 
fatal 指出每个严重的错误事件将会导致应用程序的退出。
error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
warn 表明会出现潜在的错误情形。
info 一般和在粗粒度级别上,强调应用程序的运行全程。
debug 一般用于细粒度级别上,对调试应用程序非常有帮助。
trace 是程序追踪,可以用于输出程序运行中的变量,显示执行的流程。
两个特殊的级别:OFF,可用来关闭日志记录。 ALL,启用所有消息的日志记录
一般情况下,我们只使用4个级别,优先级从高到低为 ERROR > WARN > INFO > DEBUG
组件
Log4J 主要由 Loggers (日志记录器)、Appenders(输出端)和 Layout(日志格式化器)组成。其中 Loggers 控制日志的输出级别与日志是否输出;Appenders 指定日志的输出方式(输出到控制台、文件 等);Layout 控制日志信息的输出格式
 Log4J 主要由 Loggers (日志记录器)、Appenders(输出端)和 Layout(日志格式化器)组成。其中 Loggers 控制日志的输出级别与日志是否输出;Appenders 指定日志的输出方式(输出到控制台、文件 等);Layout 控制日志信息的输出格式
Loggers
日志记录器:负责收集处理日志记录,Logger的名字大小写敏感,其命名有继承机制:例如:name为com.dream.xiaobo.Log4j的logger会继承 name为com.dream.xiaobo的logger,和JUL一致。
Log4J中有一个特殊的logger叫做“root”,他是所有logger的根,也就意味着其他所有的logger都会直接 或者间接地继承自root。root logger可以用Logger.getRootLogger()方法获取。 JUL也有一个名为.的根
Appenders
Appender和JUL的Handler很像,用来指定日志输出到哪个地方,可以同时指定日志的输出目的地。Log4j 常用的输出目的地 有以下几种:
| 输出端类型 | 
作用 | 
| ConsoleAppender | 
将日志输出到控制台 | 
| FileAppender | 
将日志输出到文件中 | 
| DailyRollingFileAppender | 
将日志输出到一个日志文件,并且每天输出到一个新的文件 | 
| RollingFileAppender | 
将日志输出到一个日志文件,并且每天输出到一个新的文件 | 
| RollingFileAppender | 
把日志信息保存到数据库中 | 
log4j占位符
%m 输出代码中指定的日志信息
%p 输出日志级别,及 DEBUG、INFO 等
%n 换行符(Windows平台的换行符为 “\n”,Unix 平台为 “\n”)
%r 输出自应用启动到输出该 log 信息耗费的毫秒数
%c 输出打印语句所属的类的全名
%t 输出产生该日志的线程全名
%d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日HH:mm:ss}
%l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10)
%F 输出日志消息产生时所在的文件名称
%L 输出代码中的行号
%% 输出一个 “%” 字符 可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式。如:
%5c 输出category名称,最小宽度是5,category<5,默认的情况下右对齐
%-5c 输出category名称,最小宽度是5,category<5,”-“号指定左对齐,会有空格
%.5c 输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格
%20.30c category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉
例
%-d{yyyy-MM-dd HH:mm:ss} [%t:%r] -[%p] %m%n
打印:日期 [线程:毫秒数] - [日志级别] - 日志信息 换行
log4j代码整理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
   | public class Log4jTest {
      public static final Logger LOGGER = Logger.getLogger(Log4jTest.class);
      @Test     public void testLog4j(){
          
 
          
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                   LOGGER.info("hello log4j");                  LOGGER.fatal("fatal");          LOGGER.error("error");          LOGGER.warn("warn");          LOGGER.info("info");          LOGGER.debug("debug");          LOGGER.trace("trace"); 
          while (true){             LOGGER.info("hello log4j");         }
      }
      @Test     public void log4jConfig(){
                   LOGGER.info("hello log4j");                  LOGGER.fatal("fatal");          LOGGER.error("error");          LOGGER.warn("warn");          LOGGER.info("info");          LOGGER.debug("debug");          LOGGER.trace("trace"); 
      } }
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
   |  log4j.rootLogger=ALL, A1, DailyRolling
 
  log4j.appender.A1=org.apache.log4j.ConsoleAppender
 
  log4j.logger.com.dream.xiaobo =DEBUG, A1, DailyRolling
  log4j.additivity.com.dream.xiaobo = false
 
  log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
 
 
  log4j.appender.FILE = org.apache.log4j.FileAppender log4j.appender.FILE.File = D:/logs/log4j.log log4j.appender.FILE.layout = org.apache.log4j.PatternLayout log4j.appender.FILE.append = true log4j.appender.FILE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
 
  log4j.appender.JDBC = org.apache.log4j.jdbc.JDBCAppender log4j.appender.JDBC.Driver = com.mysql.cj.jdbc.Driver log4j.appender.JDBC.URL = jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC log4j.appender.JDBC.User = root log4j.appender.JDBC.Password = xiaobo log4j.appender.JDBC.Sql = INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('xiaobo','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m') log4j.appender.JDBC.layout = org.apache.log4j.PatternLayout log4j.appender.JDBC.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
 
 
  log4j.appender.RollingFile = org.apache.log4j.RollingFileAppender log4j.appender.RollingFile.File = D:/logs/log4j.log log4j.appender.RollingFile.append = true log4j.appender.RollingFile.maximumFileSize = 1 log4j.appender.RollingFile.maxBackupIndex = 1
  log4j.appender.RollingFile.layout =org.apache.log4j.PatternLayout log4j.appender.RollingFile.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
 
 
  log4j.appender.DailyRolling = org.apache.log4j.DailyRollingFileAppender log4j.appender.DailyRolling.File = D:/logs/log4j.log log4j.appender.DailyRolling.append = true
  log4j.appender.DailyRolling.layout =org.apache.log4j.PatternLayout log4j.appender.DailyRolling.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
 
  | 
 
本篇文章 仅供自己学习整理 方便阅读 参考b站某UP主 如有侵权 通知即删
你知道的越多 你不知道的越多 嘿 我是小博 带你一起看我目之所及的世界……