ToB企服应用市场:ToB评测及商务社交产业平台

标题: 万字长文带你了解Java日记框架使用Java日记框架 [打印本页]

作者: 天空闲话    时间: 2024-8-14 06:04
标题: 万字长文带你了解Java日记框架使用Java日记框架
大家好,我是晓凡
一、日记概念

日记的紧张性不用我多说了,日记,简朴来说就是记录。
用来记录程序运行时发生的事变。比如,程序启动了、执行了某个操作、遇到了题目等等,这些都可以通过日记记录下来。
想象一下,你开了一家店,每天的业务额、顾客的反馈、商品的进出、库存等等,你都会记录下来。这就像是程序的日记。比如:
1.1 日记的作用

1.2 具体示例
  1. public class SimpleApp {
  2.     public static void main(String[] args) {
  3.         System.out.println("程序启动");
  4.         // 假设这里是用户输入数据
  5.         String userInput = "Hello, World!";
  6.         System.out.println("用户输入了: " + userInput);
  7.         // 处理数据
  8.         String result = processInput(userInput);
  9.         System.out.println("处理结果: " + result);
  10.         try {
  11.             //可能异常的逻辑代码
  12.         }catch(Exception e){
  13.             e.printStackTrace()
  14.         }
  15.         // 程序结束
  16.         System.out.println("程序结束");
  17.     }
  18.     private static String processInput(String input) {
  19.         // 这里是处理逻辑
  20.         return "Processed: " + input;
  21.     }
  22. }
复制代码
上面的代码我们不陌生了吧,我们使用System.out.println来打印程序的运行状态,使用e.printStackTrace()来打印信息和错误
这就是没有日记框架时,最简朴直接的日记打印方式
这种方式简朴直接,但也有一些缺点:
以是我们要引入各种功能强大的日记框架进行日记管理
二、主流日记框架

日记框架由日记门面和日记实现构成,具体如下图所示

2.1 日记门面

顾名思义,日记门面,就像是一个团队的领导者一样,只负责制定规则,安排任务,而具体干活的则交给苦逼的打工人(日记具体实现)即可。
日记门面提供了一套标准的日记记录接口,而具体的日记记录工作则由不同的日记框架来完成。
这样做的好处是,可以在不修改代码的情况下,通过配置来切换不同的日记框架。
正如职场中,一个打工人跑路了,在不需要太多本钱,不用做太多改变的情况下,新招一个更便宜的打工人也可完成同样的任务实现快速切换,好像有点扯远了
主流的日记门面框架主要有:
2.2 日记实现

通过是实现日记门面接口来完成日记记录,实实在在的打工人无疑了
主流的日记实现框架有:
​        个非常老牌的日记框架,功能非常强大,可以自定义很多日记的细节,比如日记级别、输出格式、输出目标地等。现由Apache软件基金会维护
​     也是Apache软件基金会开发,相比Log4j,Log4j2在性能上有明显提拔,同时保持了丰富的功能,支持异步日记处置惩罚,得当高性能需求的场景
​    由Log4j的原开发者之一主导开发,Spring Boot默认日记,轻量级,性能优秀,功能也比力全面
三、JUL日记框架

3.1 主要组件

3.2 使用步骤


3.3 入门案例
  1. public class LogQuickTest {
  2.     @Test
  3.     public void testLogQuick(){
  4.         //创建日志记录对象
  5.         Logger logger = Logger.getLogger("com.xiezhr");
  6.         //日志记录输出
  7.         logger.info("这是一个info日志");
  8.         logger.log(Level.INFO,"这是一个info日志");
  9.         String name="程序员晓凡";
  10.         Integer age=18;
  11.         logger.log(Level.INFO,"姓名:{0},年龄:{1}",new Object[]{name,age});
  12.     }
  13. }
复制代码

3.4 日记级别

日记级别系统,用来区分日记的紧张性
3.4.1 日记级别

3.4.2 级别关系

SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST
日记级别越高,记录的信息越紧张。当你设置一个日记级别时,比如INFO,那么INFO级别以及以上的日记(SEVERE和WARNING)都会被记录,而FINE、FINER和FINEST级别的日记则会被忽略
3.5 具体使用案例(硬编码)

这里我们按照上面的步骤创建一个日记记录器,将日记文件分别输出到控制台和文件中
  1. public class LoggingExampleTest {
  2.     @Test
  3.     public void testLogging() {
  4.         // 获取日志记录器
  5.         Logger logger = Logger.getLogger("LoggingExample");
  6.         // 设置日志级别为INFO,这意味着INFO级别及以上的日志会被记录
  7.         logger.setLevel(Level.INFO);
  8.         // 创建控制台Handler 将日志输出到控制台
  9.         // 并设置其日志级别和Formatter
  10.         ConsoleHandler consoleHandler = new ConsoleHandler();
  11.         consoleHandler.setLevel(Level.WARNING); // 控制台只输出WARNING及以上级别的日志
  12.         consoleHandler.setFormatter(new SimpleFormatter() {
  13.             @Override
  14.             public synchronized String format(LogRecord record) {
  15.                 // 自定义日志格式
  16.                 return String.format("%1$tF %1$tT [%2$s] %3$s %n", record.getMillis(), record.getLevel(), record.getMessage());
  17.             }
  18.         });
  19.         logger.addHandler(consoleHandler);
  20.         // 创建文件Handler 将日志输出到文件
  21.         // 并设置其日志级别和Formatter
  22.         try {
  23.             FileHandler fileHandler = new FileHandler("app.log", true);
  24.             fileHandler.setLevel(Level.ALL); // 文件将记录所有级别的日志
  25.             fileHandler.setFormatter(new SimpleFormatter() {
  26.                 @Override
  27.                 public synchronized String format(LogRecord record) {
  28.                     // 自定义日志格式
  29.                     return String.format("%1$tF %1$tT [%2$s] %3$s %n", record.getMillis(), record.getLevel(), record.getMessage());
  30.                 }
  31.             });
  32.             logger.addHandler(fileHandler);
  33.         } catch (IOException e) {
  34.             e.printStackTrace();
  35.         }
  36.         // 创建并设置Filter
  37.         Filter filter = new Filter() {
  38.             @Override
  39.             public boolean isLoggable(LogRecord record) {
  40.                 // 这里可以添加过滤逻辑,例如只记录包含特定字符串的日志
  41.                 return record.getMessage().contains("important");
  42.             }
  43.         };
  44.         // 将Filter应用到Logger
  45.         //logger.setFilter(filter);
  46.         // 记录不同级别的日志
  47.         logger.severe("严重错误信息 - 应记录到控制台和文件");
  48.         logger.warning("警告信息 - 应记录到控制台和文件");
  49.         logger.info("常规信息 - 只记录到文件");
  50.         logger.config("配置信息 - 只记录到文件");
  51.         logger.fine("详细日志 - 只记录到文件");
  52.         // 这条日志将被Filter过滤掉,不会记录
  53.         logger.info("这条信息不重要,将被过滤");
  54.         // 这条日志将被记录,因为消息中包含"important"
  55.         logger.info("这条信息很重要,将被记录到控制台和文件");
  56.     }
  57. }      
复制代码
① 控制台日记输出

②日记文件输出 app.log内容

代码表明
3.6 日记配置文件

以上3.4小节通过硬编码的方式打印输出日记,这样的方式很不利于后期的管理与维护,这小节我们将使用配置文件的方式进行日记输出
① 在resources下面新建logconfig.properties文件,内容如下
  1. # 指定日志处理器为:ConsoleHandler,FileHandler 表示同时使用控制台和文件处理器
  2. handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler
  3. #设置默认的日志级别为:ALL
  4. .level= ALL
  5. # 配置自定义 Logger
  6. com.xiezhr.handlers = com.xiezhr.DefConsoleHandler
  7. com.xiezhr.level = CONFIG
  8. # 如果想要使用自定义配置,需要关闭默认配置
  9. com.xiezhr.useParentHanlders =true
  10. # 向日志文件输出的 handler 对象
  11. # 指定日志文件路径 当文件数为1时 日志为/logs/java0.log
  12. java.util.logging.FileHandler.pattern = /logs/java%u.log
  13. # 指定日志文件内容大小,下面配置表示日志文件达到 50000 字节时,自动创建新的日志文件
  14. java.util.logging.FileHandler.limit = 50000
  15. # 指定日志文件数量,下面配置表示只保留 1 个日志文件
  16. java.util.logging.FileHandler.count = 1
  17. # 指定 handler 对象日志消息格式对象
  18. java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
  19. # 指定 handler 对象的字符集为 UTF-8 ,防止出现乱码
  20. java.util.logging.FileHandler.encoding = UTF-8
  21. # 指定向文件中写入日志消息时,是否追加到文件末尾,true 表示追加,false 表示覆盖
  22. java.util.logging.FileHandler.append = true
  23. # 向控制台输出的 handler 对象
  24. # 指定 handler 对象的日志级别
  25. java.util.logging.ConsoleHandler.level =WARNING
  26. # 指定 handler 对象的日志消息格式对象
  27. java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
  28. # 指定 handler 对象的字符集
  29. java.util.logging.ConsoleHandler.encoding = UTF-8
  30. # 指定日志消息格式
  31. java.util.logging.SimpleFormatter.format = [%1$tF %1$tT] %4$s: %5$s %n
复制代码
注意: 设置日记消息格式中(背面一小节会具体讲解)
② 日记测试
  1. @Test
  2. public void testLogProperties()throws Exception{
  3.     // 1、读取配置文件,通过类加载器
  4.     InputStream ins = LoggingExampleTest.class.getClassLoader().getResourceAsStream("logconfig.properties");
  5.     // 2、创建LogManager
  6.     LogManager logManager = LogManager.getLogManager();
  7.     // 3、通过LogManager加载配置文件
  8.     logManager.readConfiguration(ins);
  9.     // 4、创建日志记录器
  10.     Logger logger = Logger.getLogger("com.xiezhr");
  11.     // 5、记录不同级别的日志
  12.     logger.severe("这是一条severe级别信息");
  13.     logger.warning("这是一条warning级别信息");
  14. }
复制代码
执行上面代码后
控制台输出

java0.log文件输出:

3.7 日记格式化

上面两个小节中,不管是通过编码大概配置文件 都对日记进行了格式化
① 编码设置日记格式
  1. fileHandler.setFormatter(new SimpleFormatter() {
  2.     @Override
  3.     public synchronized String format(LogRecord record) {
  4.         // 自定义日志格式
  5.         return String.format("%1$tF %1$tT [%2$s] %3$s %n", record.getMillis(), record.getLevel(), record.getMessage());
  6.     }
  7. });
复制代码
② 配置文件指定日记格式
  1. # 指定日志消息格式
  2. java.util.logging.SimpleFormatter.format = [%1$tF %1$tT] %4$s: %5$s %n
复制代码
上面设置的日记格式设置你看懂了么?
不管是哪种方式设置日记格式,我们看源码最终都是通过String.format函数来实现的,所有我们有必要学一学String类提供的format这个方法的使用

3.7.1 String的format方法

String的format方法用来格式化字符串。
format方法就像是一个模板,你可以在这个模板里插入你想要的数据,然后它就会帮你生成一个格式化好的字符串。
我们先来看看下面这个简朴例子
  1. @Test
  2. public void testStringFormatter()throws Exception{
  3.     String name = "晓凡";
  4.     Integer age = 18;
  5.     // 使用String.format()方法格式化字符串
  6.     String xiaofan = String.format("%s今年%d岁", name, age);
  7.     System.out.println(xiaofan);
  8. }
  9. //输出
  10. 晓凡今年18岁
复制代码
3.7.2 常用占位符

%s和%d 为占位符,不同范例需要不同占位符,那么另有哪些常用转换符呢?
占位符具体说明示例%s字符串范例****“喜欢晓凡请关注”%c字符范例‘x’%b布尔范例true%d整数范例(十进制)666%x整数范例(十六进制)FF%o整数范例(八进制)77%f浮点范例8.88%a十六进制浮点范例FF.34%e指数范例1.28e+5%n换行符%tx日期和时间范例(x代表不同的日期与时间转换符)3.7.3 特殊符号搭配使用

符号说明示例效果0指定数字、字符前面补0,用于对齐("%04d",6)0006空格指定数字、字符前面补空格,用于对齐("[% 4s]",x)[   x],以“,”对数字分组显示(常用于金额)("%,f,666666.66")666,666.6600注意: 默认情况下,可变参数是按照次序依次更换,但是我们可以通过“数字$”来重复使用可变参数
  1. @Test
  2. public void testStringFormatter()throws Exception{
  3.     String name = "晓凡";
  4.     Integer age = 18;
  5.     // 使用String.format()方法格式化字符串
  6.     String xiaofan = String.format("%s今年%d岁", name, age);
  7.     System.out.println(xiaofan);
  8.     //
  9.     String xiaofan1 = String.format("%s今年%d岁,%1$s的公众号是:程序员晓凡", name, age);
  10.     System.out.println(xiaofan1);
  11. }
  12. //输出
  13. 晓凡今年18岁
  14. 晓凡今年18岁,晓凡的公众号是:程序员晓凡
复制代码
上面例子中我们通过%1$s重复使用第一个参数name
3.7.4 日期格式化

上面我们说到%tx,x代表日期转换符,其具体含义如下
符号描述示例c包含全部日期和时间信息周六 8月 03 17:16:37 CST 2024F"年-月-日" 格式2024-08-03D"月/日/年"格式08/03/24d03r“HH:MM:SS PM”格式(12小时制)05:16:37 下午R“HH:MM”格式(24小时制)17:16T“HH:MM:SS ”格式(24小时制)17:16:37b月份本地化8月y两位年24Y四位年2024m08H时(24小时制)17I时(12小时制)05M16S37s秒为单位的时间戳1722677530p上午照旧下午下午四、Log4j日记框架

Log4j 是Apache软件基金组织旗下的一款开源日记框架,是一款比力老的日记框架,目前已出log4j2,它在log4j上做了很大改动,性能提拔了不少。但是有些老项目还会在使用,以是我们也来说一说
官网:https://logging.apache.org/log4j/1.x/
注意: 从官网,我们可以看到项目管理委员会公布Log4j 1. x已制止使用。建议用户升级到 Log4j 2

4.1 快速入门

4.1.1 添加依靠
  1. <dependency>
  2.     <groupId>log4j</groupId>
  3.     <artifactId>log4j</artifactId>
  4.     <version>1.2.17</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>junit</groupId>
  8.     <artifactId>junit</artifactId>
  9.     <version>4.13.2</version>
  10.     <scope>test</scope>
  11. </dependency>
复制代码
4.1.2 log4j入门代码
  1. @Test
  2. public void testLog4jQuick(){
  3.     //初始化日志配置信息,不需要配置文件
  4.     BasicConfigurator.configure();
  5.     //获取日志记录器
  6.     Logger logger = Logger.getLogger(Log4jTest.class);
  7.     //通过各种日志级别打印日志
  8.     logger.fatal("这是一条致命的信息");  // 严重错误,一般会造成系统崩溃
  9.     logger.error("这是一条错误的信息");  // 出现错误时,比如出错了但是不影响系统继续运行
  10.     logger.warn("这是一条警告的信息");   // 警告级别,比如要告警的时候
  11.     logger.info("这是一条普通的信息");  // 一般信息,比如记录普通的方法执行
  12.     logger.debug("这是一条调试的信息"); // 调试信息,比如调试的时候打印的信息
  13.     logger.trace("这是一条追踪的信息");  // 追踪信息,比如追踪程序运行路径
  14. }
  15. //输出
  16. 0 [main] FATAL Log4jTest  - 这是一条致命的信息
  17. 0 [main] ERROR Log4jTest  - 这是一条错误的信息
  18. 0 [main] WARN Log4jTest  - 这是一条警告的信息
  19. 0 [main] INFO Log4jTest  - 这是一条普通的信息
  20. 0 [main] DEBUG Log4jTest  - 这是一条调试的信息
复制代码
注意: BasicConfigurator.configure(); 为log4j在不添加配置文件的情况下初始化默认日记配置信息,如果既没有默认配置信息,也没有配置文件
会报下面错误

4.2 日记级别

日记级别,就比如是日记本里的不同标记,用来区分信息的紧张性。在log4j中,日记级别从低到高分为以下几种:
出了上面的,另有以下两个特殊级别
  1. 1. **OFF**: 用来关闭日志记录
  2. 1. **ALL**: 启用所有消息的日志记录
复制代码
4.3 Log4j组件

4.3.1 Logger

Log4j中有一个特殊的logger叫做root,它是logger的根,其他的logger都会直接大概间接的继续自root。
入门示例中,我们通过Logger.getLogger(Log4jTest.class); 获取的就是root logger
name为org.apache.commons 的logger会继续name为org.apache的logger
4.3.2 Appender

用来指定日记记录到哪儿,主要有以下几种
Appender范例作用ConsoleAppender将日记输出到控制台FileAppender将日记输出到文件中DailyRollingFileAppender将日记输出到文件中,并且每天输出到一个日记文件中RollingFileAppender将日记输出到文件中,并且指定文件的大小,当文件大于指定大小,会生成一个新的日记文件JDBCAppender将日记生存到数据库中4.3.3 Layout

用于控制日记内容输出格式,Log4j常用的有以下几种输出格式
日记格式器说明HTMLLayout将日记以html表格形式输出SimpleLayout简朴的日记格式输出,例如(info-message)PatternLayout最强大的格式化器,也是我们使用最多的一种,我们可以自定义输出格式示例:下面我们通过PatternLayout 格式化日记
  1. @Test
  2. public void testLog4jLayout(){
  3.     //初始化日志配置信息,不需要配置文件
  4.     BasicConfigurator.configure();
  5.     //获取日志记录器
  6.     Logger logger = Logger.getLogger(Log4jTest.class);
  7.     Layout patternLayout = new PatternLayout("%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n");// 将自定义的Layout应用到控制台Appender上
  8.     ConsoleAppender consoleAppender = new ConsoleAppender(patternLayout);
  9.     logger.addAppender(consoleAppender);
  10.     // 记录日志
  11.     logger.info("这是一条自定义格式的日志信息");
  12. }
  13. //输出
  14. 2024-08-04 13:55:35 [INFO] - Log4jTest.testLog4jLayout(Log4jTest.java:44) - 这是一条自定义格式的日志信息
复制代码
占位符说明%m输出代码中指定的日记信息%p输出优先级%n换行符%r输出自应用启用到输出log信息消耗的毫秒数%c输出语句所属的类全名%t输出线程全名%d输出服务器当前时间,%d%l输出日记时间发生的位置,包括类名、线程、及在代码中的函数 例如: Log4jTest.testLog4jLayout(Log4jTest.java:44)%F输出日记消息产生时所在的文件夹名称%L输出代码中的行号%5ccategory名称不足5位时,左边增补空格,即右对齐%-5ccategory名称不足5位时,右边增补空格,即左对齐.5ccategory名称大于5位时,会将左边多出的字符截取掉,小于5位时,以空格增补4.4 通过配置文件配置日记

BasicConfigurator.configure(); 上面代码中通过这段代码初始化日记配置信息,这一小节,我们通过配置文件来配置
通过看LogManager日记管理器源码,我们知道可以默认加载如下几种格式的配置文件(此中log4j.xml 和log4j.properties 是我们最常用的)
  1. # 指定RootLogger顶级父元素默认配置信息
  2. # 指定日志级别位INFO,使用的appender 位Console
  3. log4j.rootLogger=INFO,Console
  4. # 指定控制台日志输出appender
  5. log4j.appender.Console = org.apache.log4j.ConsoleAppender
  6. # 指定消息格式器 layout
  7. log4j.appender.Console.layout=org.apache.log4j.PatternLayout
  8. # 指定消息内容格式
  9. log4j.appender.Console.layout.conversionPattern =%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n
复制代码
大概
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Configuration>
  3.     <Appenders>
  4.         <Console name="Console" target="SYSTEM_OUT">
  5.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  6.         </Console>
  7.     </Appenders>
  8.     <Loggers>
  9.         <Root level="INFO">
  10.             <AppenderRef ref="Console"/>
  11.         </Root>
  12.     </Loggers>
  13. </Configuration>
复制代码
4.5 各种日记输出示例

上面小节中已经说了控制台输出配置,由于篇幅缘故因由,这里不再赘述
① 文件输出配置
  1. # 指定RootLogger顶级父元素默认配置信息
  2. # 指定日志级别位INFO,使用的appender 位Console
  3. log4j.rootLogger=INFO,File
  4. # 指定文件日志输出appender
  5. log4j.appender.File = org.apache.log4j.FileAppender
  6. #  指定日志文件名
  7. log4j.appender.File.File=D:/logs/testxiezhr.log
  8. #  指定是否在原有日志的基础添加新日志
  9. log4j.appender.File.Append=true
  10. # 指定消息格式器 layout
  11. log4j.appender.File.layout=org.apache.log4j.PatternLayout
  12. # 指定消息内容格式
  13. log4j.appender.File.layout.conversionPattern =%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n
  14. # 指定日志文件编码格式
  15. log4j.appender.File.encoding=UTF-8
复制代码
②日记文件根据大小分割输出
  1. # 指定RootLogger顶级父元素默认配置信息
  2. # 指定日志级别位INFO,使用的appender 位Console
  3. log4j.rootLogger=INFO,RollingFile
  4. # 指定文件日志根据大小分割输出appender
  5. log4j.appender.RollingFile = org.apache.log4j.RollingFileAppender
  6. #  指定日志文件名
  7. log4j.appender.RollingFile.File=D:/logs/testxiezhr.log
  8. #  设置是否在重新启动服务时,在原有日志的基础添加新日志
  9. log4j.appender.RollingFile.Append=true
  10. # 设置最多保存的日志文件个数
  11. log4j.appender.RollingFile.MaxBackupIndex=5
  12. # 设置文件大小,超过这个值,就会再产生一个文件
  13. log4j.appender.RollingFile.maximumFileSize=1
  14. # 指定消息格式器 layout
  15. log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout
  16. # 指定消息内容格式
  17. log4j.appender.RollingFile.layout.conversionPattern =%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n
  18. # 指定日志文件编码格式
  19. log4j.appender.RollingFile.encoding=UTF-8
复制代码
最终生成日记效果如下所示

③ 日记文件根据日期分割
  1. # 指定RootLogger顶级父元素默认配置信息
  2. # 指定日志级别位INFO,使用的appender 位Console
  3. log4j.rootLogger=INFO,DailyRollingFile
  4. # 指定文件日志根据日期分割输出appender
  5. log4j.appender.DailyRollingFile = org.apache.log4j.DailyRollingFileAppender
  6. #  指定日志文件名
  7. log4j.appender.DailyRollingFile.File=D:/logs/testxiezhr.log
  8. #  设置是否在重新启动服务时,在原有日志的基础添加新日志
  9. log4j.appender.DailyRollingFile.Append=true
  10. # 指定消息格式器 layout
  11. log4j.appender.DailyRollingFile.layout=org.apache.log4j.PatternLayout
  12. # 指定消息内容格式
  13. log4j.appender.DailyRollingFile.layout.conversionPattern =%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n
  14. # 指定日志文件编码格式
  15. log4j.appender.DailyRollingFile.encoding=UTF-8
复制代码
最终生成日记效果如下所示

④ 自定义日记配置
当我们想定义自己的日记配置时,可以按照如下配置添加.例如:添加com.xiezhr,它也是继续自rootLogger,以是我们必须要添加
log4j.additivity.com.xiezhr=false 避免日记打印重复
  1. # 指定RootLogger顶级父元素默认配置信息
  2. # 指定日志级别位INFO,使用的appender 位Console
  3. log4j.rootLogger=INFO,DailyRollingFile
  4. # 自定义日志配置
  5. log4j.logger.com.xiezhr=DEBUG,Console
  6. # 设置日志叠加,这一句配置一定要添加,否则日志会重复输出
  7. log4j.additivity.com.xiezhr=false
复制代码
⑤ 将日记信息存入数据库
起首,我们新建一个testlog数据库,并在数据库下新建log日记表
  1. CREATE TABLE `log` (
  2.   `log_id` int(11) NOT NULL AUTO_INCREMENT,
  3.   `project_name` varchar(255) DEFAULT NULL COMMENT '目项名',
  4.   `create_date` varchar(255) DEFAULT NULL COMMENT '创建时间',
  5.   `level` varchar(255) DEFAULT NULL COMMENT '优先级',
  6.   `category` varchar(255) DEFAULT NULL COMMENT '所在类的全名',
  7.   `file_name` varchar(255) DEFAULT NULL COMMENT '输出日志消息产生时所在的文件名称 ',
  8.   `thread_name` varchar(255) DEFAULT NULL COMMENT '日志事件的线程名',
  9.   `line` varchar(255) DEFAULT NULL COMMENT '号行',
  10.   `all_category` varchar(255) DEFAULT NULL COMMENT '日志事件的发生位置',
  11.   `message` varchar(4000) DEFAULT NULL COMMENT '输出代码中指定的消息',
  12.   PRIMARY KEY (`log_id`)
  13. );
复制代码
其次,新建JDBCAppender,并且为JDBCAppender 设置数据库连接信息,具体代码如下
  1. @Test
  2. public void testLog4j2db(){
  3.     //初始化日志配置信息,不需要配置文件
  4.     BasicConfigurator.configure();
  5.     //获取日志记录器
  6.     Logger logger = Logger.getLogger(Log4jTest.class);
  7.     // 新建JDBCAppender
  8.     JDBCAppender jdbcAppender = new JDBCAppender();
  9.     jdbcAppender.setDriver("com.mysql.cj.jdbc.Driver");
  10.     jdbcAppender.setURL("jdbc:mysql://localhost:3308/testlog?useSSL=false&serverTimezone=UTC");
  11.     jdbcAppender.setUser("root");
  12.     jdbcAppender.setPassword("123456");
  13.     jdbcAppender.setSql("INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('晓凡日志测试','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')");
  14.     logger.addAppender(jdbcAppender);
  15.     // 记录日志
  16.     logger.info("这是一条自定义格式的日志信息");
  17.     logger.error("这是一条自定义格式的错误日志信息");
  18. }
复制代码
最后,运行代码,来看一下效果

五、JCL日记门面

作甚日记门面,我们在第二小节中已经介绍过了,这里就不多说了。
日记门面的引入,使得我们可以面向接口开发,不再依靠具体的实现类,减小代码耦合。
JCL全称Jakarta Commons Logging是Apache提供的一个通用日记API,JCL中自带一个日记实现simplelog,不过这个功能非常简朴

5.1 JCL快速入门

① LCL的两个抽象类
② 示例代码
引入依靠
  1. <dependency>
  2.     <groupId>commons-logging</groupId>
  3.     <artifactId>commons-logging</artifactId>
  4.     <version>1.2</version>
  5. </dependency>
复制代码
根本代码
我们没有导入任何日记实现,以是这里默认使用jdk自带JUL来实现日记
  1. @Test
  2. public void test(){
  3.     Log log = LogFactory.getLog(JclTest.class);
  4.     log.error("这是一条error");
  5.     log.warn("这是一条warn");
  6.     log.info("这是一条info");
  7.     log.debug("这是一条debug");
  8.     log.trace("这是一条trace");
  9. }
复制代码

5.2 快速切换Log4j日记框架

① 导入log4j日记依靠
  1. <dependency>
  2.     <groupId>log4j</groupId>
  3.     <artifactId>log4j</artifactId>
  4.     <version>1.2.17</version>
  5. </dependency>
复制代码
② 添加log4j.properties配置文件
  1. # 指定RootLogger顶级父元素默认配置信息
  2. # 指定日志级别位INFO,使用的appender 位Console
  3. log4j.rootLogger=INFO,Console
  4. # 指定控制台日志输出appender
  5. log4j.appender.Console = org.apache.log4j.ConsoleAppender
  6. # 指定消息格式器 layout
  7. log4j.appender.Console.layout=org.apache.log4j.PatternLayout
  8. # 指定消息内容格式
  9. log4j.appender.Console.layout.conversionPattern =%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n
复制代码
③ 测试日记输出
  1. @Test
  2. public void testJclLog4j(){
  3.     Log log = LogFactory.getLog(JclLog4jTest.class);
  4.     log.error("这是一条error");
  5.     log.warn("这是一条warn");
  6.     log.info("这是一条info");
  7.     log.debug("这是一条debug");
  8.     log.trace("这是一条trace");
  9. }
复制代码
日记输出如下:

我们可以看到,使用了JCL日记门面之后,我们从simplelog日记框架切换到log4j日记框架,没有改过代码。
六、SLF4j日记门面

SLF4j 全称是Simple Logging Facade For JavaJava简朴的日记门面 和上一小节说到的JCL干的一样的活。
在现目前的大多数Java项目中,日记框架根本上会选择slf4j-api 作为门面,配上具体实现框架logback、log4j 等使用
SLF4j是目前市面上最流行的日记门面,主要提供了以下两个功能
6.1 快速入门

① 添加依靠
  1. <dependency>
  2.       <groupId>org.slf4j</groupId>
  3.       <artifactId>slf4j-api</artifactId>
  4.       <version>2.0.13</version>
  5. </dependency>
  6. <dependency>
  7.       <groupId>org.slf4j</groupId>
  8.       <artifactId>slf4j-simple</artifactId>
  9.       <version>2.0.13</version>
  10.   </dependency>
复制代码
②日记输出
  1. //申明日志对象
  2. public final  static Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
  3. @Test
  4. public void testSlf4j(){
  5.     //打印日志
  6.     logger.error("这是error日志");
  7.     logger.warn("这是warn日志");
  8.     logger.info("这是info日志");
  9.     logger.debug("这是debug日志");
  10.     logger.trace("这是trace日志");
  11.     //使用占位符输出日志信息
  12.     String name = "晓凡";
  13.     Integer age = 18;
  14.     logger.info("{},今年{}岁", name, age);
  15.     //将系统异常写入日志
  16.     try {
  17.         int i = 1/0;
  18.     }catch (Exception e){
  19.         logger.error("执行出错", e);
  20.     }
  21. }
复制代码
上面代码输出日记如下

6.2 SLF4j 日记绑定功能

6.2.1 日记绑定原理

下图是从官网薅下来的slf4j 日记绑定图,对了,官网在这https://www.slf4j.org/

小同伴看到上图大概会有点懵,满是英文,看不懂。

于是乎,晓凡简朴翻译了一下,如下如所示

6.2.2 绑定logback日记框架

① 引入logback依靠
  1. <dependency>
  2.     <groupId>ch.qos.logback</groupId>
  3.     <artifactId>logback-classic</artifactId>
  4.     <version>1.4.14</version>
  5. </dependency>
复制代码
② 日记输出
快速入门中代码不变,运行后,采用logback日记框架输入日记如下所示

6.2.3 绑定slf4j-nop

① 引入依靠
  1. <dependency>
  2.     <groupId>org.slf4j</groupId>
  3.     <artifactId>slf4j-nop</artifactId>
  4.     <version>2.0.13</version>
  5. </dependency>
复制代码
② 此时控制台将不会输出任何日记
6.2.4 使用适配器绑定log4j日记框架

① 导入依靠
  1.     org.slf4j    slf4j-log4j12    2.0.13<dependency>
  2.     <groupId>log4j</groupId>
  3.     <artifactId>log4j</artifactId>
  4.     <version>1.2.17</version>
  5. </dependency>
复制代码
② 添加log4j.properties配置文件
  1. # 指定RootLogger顶级父元素默认配置信息
  2. # 指定日志级别位INFO,使用的appender 位Console
  3. log4j.rootLogger=INFO,Console
  4. # 指定控制台日志输出appender
  5. log4j.appender.Console = org.apache.log4j.ConsoleAppender
  6. # 指定消息格式器 layout
  7. log4j.appender.Console.layout=org.apache.log4j.PatternLayout
  8. # 指定消息内容格式
  9. log4j.appender.Console.layout.conversionPattern =%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n
复制代码
③ 代码不变,日记输出如下

6.2.5 使用适配器绑定JUL日记框架

① 引入依靠
  1. <dependency>
  2.     <groupId>org.slf4j</groupId>
  3.     <artifactId>slf4j-jdk14</artifactId>
  4.     <version>2.0.13</version>
  5. </dependency>
复制代码
② 代码不变,日记输出如下

6.3 SLF4j日记桥接

6.3.1 使用场景

如果你的项目中已经使用了Log4j 1.x等老的日记框架,但你想迁移到使用SLF4J的API,这时间你可以使用SLF4J的Log4j 1.x桥接器来平滑过渡
6.3.2 桥接原理


上图为SLF4j官网提供的桥接原理图,从图中,我们可以看到,只需要引入不同的桥接器log4j-over-slf4j、jul-to-slf4j 、jcl-over-slf4j
就可以实现在不改变原有代码的情况下,将日记从log4j、jul、jcl迁移到slf4j+logback日记组合
6.3.3 桥接步骤

下面以Log4j 1.x迁移到slf4j+logback日记组合为例
​       


七、Logback日记框架

官网:https://logback.qos.ch/index.html
7.1 快速入门

① 添加依靠
  1.     org.slf4j    slf4j-api    2.0.13<dependency>
  2.     <groupId>ch.qos.logback</groupId>
  3.     <artifactId>logback-classic</artifactId>
  4.     <version>1.4.14</version>
  5. </dependency>
复制代码
② 打印日记代码
  1. public class LogbackTest {
  2.     private static final Logger logger = LoggerFactory.getLogger(LogbackTest.class);
  3.     @Test
  4.     public void testLogbackQuick(){
  5.         logger.error("这是一个错误日志");
  6.         logger.warn("这是一个警告日志");
  7.         logger.info("这是一个信息日志");
  8.         logger.debug("这是一个调试日志");
  9.         logger.trace("这是一个跟踪日志");
  10.     }
  11. }
复制代码

7.2 Logback配置

Logback可以通过编程式配置(添加配置类的方式),也可以通过配置文件配置。
配置文件是日常开发中最常用的,我们这里就以这种方式配置,如果对配置文件感兴趣的小同伴可自行到官网检察
7.2.1  Logback 包含哪些组件?

7.2.2 可以有哪些文件格式进行配置?

Logback会依次读取以下范例配置文件
7.2.3 添加一个ConsoleAppender控制台日记输出配置

配置文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3.    
  4.    
  5.     <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread]%-5level %msg%n" />
  6.    
  7.     <appender name="console" >
  8.         <encoder>
  9.             
  10.             <pattern>${pattern}</pattern>
  11.         </encoder>
  12.     </appender>
  13.    
  14.     <root level="ALL">
  15.         
  16.         <appender-ref ref="console" />
  17.     </root>
  18. </configuration>
复制代码
日记输入如下

日记输出格式:在前面几个日记框架中我们已经介绍过,大同小异。这里简朴说下常用的几种
符号含义%d{pattern}格式化日期%m大概%msg日记信息%Mmethod(方法)%L行号%c完整类名称%thread线程名称%n换行%-5level日记级别,并且左对齐7.2.4 添加一个FileAppender将日记输出到文件

配置文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3.    
  4.    
  5.     <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread]%-5level %msg%n" />
  6.    
  7.     <property name="log_file" value="d:/logs"></property>
  8.    
  9.     <appender name="file" >
  10.         <encoder>
  11.             
  12.             <pattern>${pattern}</pattern>
  13.         </encoder>
  14.         
  15.         <file>${log_file}/logback.log</file>
  16.     </appender>
  17.    
  18.     <root level="ALL">
  19.         
  20.         <appender-ref ref="file" />
  21.     </root>
  22. </configuration>
复制代码
日记输出如下

7.2.5 生成html格式appender对象
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Configuration>
  3.     <Appenders>
  4.         <Console name="Console" target="SYSTEM_OUT">
  5.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  6.         </Console>
  7.     </Appenders>
  8.     <Loggers>
  9.         <Root level="INFO">
  10.             <AppenderRef ref="Console"/>
  11.         </Root>
  12.     </Loggers>
  13. </Configuration>        ${pattern}<appender name="async" >
  14.     <appender-ref ref="console" />
  15. </appender>
  16. <root level="ALL">
  17.    
  18.     <appender-ref ref="console" />
  19.    
  20.     <appender-ref ref="async" />        
  21. </root>        ${log_file}/logback.html<appender name="async" >
  22.     <appender-ref ref="console" />
  23. </appender>
  24. <root level="ALL">
  25.    
  26.     <appender-ref ref="console" />
  27.    
  28.     <appender-ref ref="async" />        
  29. </root>   
复制代码
日记输出: 在d:/logs目录下生成一个logback.html 文件

7.3 Logback 日记拆分压缩 ⭐

在生产情况中对日记进行按时间、日记大小拆分 且压缩日记非常非常紧张,以是单独拿出来说一说
配置文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3.    
  4.    
  5.     <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M %L [%thread] %m %n" />
  6.    
  7.     <property name="log_file" value="d:/logs"></property>
  8.    
  9.     <appender name="rollFile" >
  10.         <encoder >
  11.             
  12.             <pattern>${pattern}</pattern>
  13.         </encoder>
  14.         
  15.         <file>${log_file}/roll_logback.log</file>
  16.         
  17.         <rollingPolicy >
  18.             
  19.             <fileNamePattern>${log_file}/roll_logback.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern>
  20.             
  21.             <maxFileSize>1MB</maxFileSize>
  22.             
  23.             <MaxHistory>3</MaxHistory>
  24.         </rollingPolicy>
  25.     </appender>
  26.    
  27.     <root level="ALL">
  28.         
  29.         <appender-ref ref="rollFile" />
  30.     </root>
  31. </configuration>
复制代码
日记滚动输出: 按照日期和文件大小进行拆分

7.4 异步日记

我们先来表明下什么是异步日记?
我们将日记输出到文件中,这样会涉及到大量io操作,非常耗时,如果需要输出大量的日记,就大概影响正常的主线程业务逻辑。
为了解决这题目,异步日记就出现了。日记信息不是直接写入到日记文件大概控制台,而是先发送到一个队列里,
然后由一个专门的线程去处置惩罚这些日记信息的写入工作。
这样做的好处是可以减少日记记录对主程序运行的影响,提高程序的服从。
7.4.1 不加异步日记
  1. private static final Logger logger = LoggerFactory.getLogger(LogbackTest.class);
  2.     @Test
  3.     public void testLogbackQuick(){
  4.         //日志输出
  5.         logger.error("这是一个错误日志");
  6.         logger.warn("这是一个警告日志");
  7.         logger.info("这是一个信息日志");
  8.         logger.debug("这是一个调试日志");
  9.         logger.trace("这是一个跟踪日志");
  10.         //这里模拟业务逻辑
  11.         System.out.println("晓凡今年18岁了");
  12.         System.out.println("晓凡的个人博客是:www.xiezhrspace.cn");
  13.         System.out.println("晓凡的个人公众号是:程序员晓凡");
  14.         System.out.println("晓凡的个人微信是:xie_zhr");
  15.         System.out.println("欢迎关注晓凡,持续输出干货!!!!!");
  16.     }
复制代码
输出效果:

从上面控制台输出看,只有当日记输出完成之后我们的业务逻辑代码才被执行。如果日记耗时比力长,非常影响服从
7.4.2 添加异步日记

我们只需在原来的配置文件中添加如下关键配置
  1. <appender name="async" >
  2.     <appender-ref ref="console" />
  3. </appender>
  4. <root level="ALL">
  5.    
  6.     <appender-ref ref="console" />
  7.    
  8.     <appender-ref ref="async" />        
  9. </root>
复制代码
日记输出效果:

从上面日记日记输出看,不再是日记输出完再进行业务逻辑代码执行,而是异步执行了
八、Log4j2日记框架

官网:https://logging.apache.org/log4j/2.x/
Log4j2是Log4j的升级版,参考了Logback的一些优秀设计,修复了一些bug,性能和功能都带来了极大提拔
主要体现在以下几个方面
Log4j2有这么多优势,以是在将来SLF4j+Log4j2组合
8.1 快速入门

Log4j2不光仅是日记实现,同时也是日记门面。在快速入门中,我们就使用Log4j2作为日记门面和日记实现来快速入门
8.1.1 添加依靠
  1. <dependency>
  2.     <groupId>org.apache.logging.log4j</groupId>
  3.     <artifactId>log4j-api</artifactId>
  4.     <version>2.23.1</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.apache.logging.log4j</groupId>
  8.     <artifactId>log4j-core</artifactId>
  9.     <version>2.23.1</version>
  10. </dependency>
复制代码
8.1.2 添加日记实当代码
  1. public class Log4j2Test {
  2.     private static final Logger logger = LogManager.getLogger(Log4j2Test.class);
  3.     @Test
  4.     public void Log4j2Test(){
  5.         logger.fatal("这是一条致命信息");
  6.         logger.error("这是一条错误信息");
  7.         logger.warn("这是一条警告信息");
  8.         logger.info("这是一条一般信息");
  9.         logger.debug("这是一条调试信息");
  10.         logger.trace("这是一条追踪信息");
  11.     }
  12. }
复制代码
日记输出效果如下

8.2 使用slf4j+log4j2组合

前面我们提到SLF4j+Log4j2组合会是将来日记发展的大趋势,以是接下来我们就使用这个组合来输出日记
导入依靠
  1. <dependency>
  2.     <groupId>org.apache.logging.log4j</groupId>
  3.     <artifactId>log4j-api</artifactId>
  4.     <version>2.23.1</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.apache.logging.log4j</groupId>
  8.     <artifactId>log4j-core</artifactId>
  9.     <version>2.23.1</version>
  10. </dependency>    org.slf4j    slf4j-api    2.0.13        org.apache.logging.log4j    log4j-slf4j-impl    2.23.1
复制代码
日记输出代码
  1. public class Log4j2Test {
  2.         //这里我们换成了slf4j的门面接口
  3.     private static final Logger logger = LoggerFactory.getLogger(Log4j2Test.class);
  4.     @Test
  5.     public void Log4j2Test(){
  6.         logger.error("这是一条错误信息");
  7.         logger.warn("这是一条警告信息");
  8.         logger.info("这是一条一般信息");
  9.         logger.debug("这是一条调试信息");
  10.         logger.trace("这是一条追踪信息");
  11.     }
  12. }
复制代码
日记输出效果

8.3 Log4j2配置

log4j2 默认加载classpath 下的 log4j2.xml 文件中的配置。
下面通过log4j2.xml 配置文件进行测试,配置大同小异,这里就不一一说明白,给出完整的配置
  1.                 D:/logs<?xml version="1.0" encoding="UTF-8"?>
  2. <Configuration>
  3.     <Appenders>
  4.         <Console name="Console" target="SYSTEM_OUT">
  5.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  6.         </Console>
  7.     </Appenders>
  8.     <Loggers>
  9.         <Root level="INFO">
  10.             <AppenderRef ref="Console"/>
  11.         </Root>
  12.     </Loggers>
  13. </Configuration><?xml version="1.0" encoding="UTF-8"?>
  14. <Configuration>
  15.     <Appenders>
  16.         <Console name="Console" target="SYSTEM_OUT">
  17.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  18.         </Console>
  19.     </Appenders>
  20.     <Loggers>
  21.         <Root level="INFO">
  22.             <AppenderRef ref="Console"/>
  23.         </Root>
  24.     </Loggers>
  25. </Configuration><?xml version="1.0" encoding="UTF-8"?>
  26. <Configuration>
  27.     <Appenders>
  28.         <Console name="Console" target="SYSTEM_OUT">
  29.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  30.         </Console>
  31.     </Appenders>
  32.     <Loggers>
  33.         <Root level="INFO">
  34.             <AppenderRef ref="Console"/>
  35.         </Root>
  36.     </Loggers>
  37. </Configuration><?xml version="1.0" encoding="UTF-8"?>
  38. <Configuration>
  39.     <Appenders>
  40.         <Console name="Console" target="SYSTEM_OUT">
  41.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  42.         </Console>
  43.     </Appenders>
  44.     <Loggers>
  45.         <Root level="INFO">
  46.             <AppenderRef ref="Console"/>
  47.         </Root>
  48.     </Loggers>
  49. </Configuration><?xml version="1.0" encoding="UTF-8"?>
  50. <Configuration>
  51.     <Appenders>
  52.         <Console name="Console" target="SYSTEM_OUT">
  53.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  54.         </Console>
  55.     </Appenders>
  56.     <Loggers>
  57.         <Root level="INFO">
  58.             <AppenderRef ref="Console"/>
  59.         </Root>
  60.     </Loggers>
  61. </Configuration><?xml version="1.0" encoding="UTF-8"?>
  62. <Configuration>
  63.     <Appenders>
  64.         <Console name="Console" target="SYSTEM_OUT">
  65.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  66.         </Console>
  67.     </Appenders>
  68.     <Loggers>
  69.         <Root level="INFO">
  70.             <AppenderRef ref="Console"/>
  71.         </Root>
  72.     </Loggers>
  73. </Configuration>        
复制代码
日记输出如下

下面的截图为2024-08-11的日记按日记文件大小1MB拆分成10个并进行压缩,拆分满10个文件后新日记会覆盖旧日记,其他天的类似

8.4 Log4j2 异步日记

Log4j2最大的特点就是异步日记,就因为异步日记的存在,将性能提拔了好多。
下图是官网给的性能对比图,从图中我们可以看出在全局异步模式(Loggers all async) 和混淆异步模式(Loggers mixed sync/async)
性能简直将Logback和Log4j日记框架甩了一条街。
至于什么时全局异步模式和混淆异步模式?我们会在背面具体说明

8.4.1 陌生名词表明

8.4.2 同步日记与异步日记


2、异步日记流程

8.5 异步日记配置

异步日记的实现一共有两种方式
第一种方式因为用的不多性能也不够好,以是这里就不说了,我们以第二种配置来具体说一说
不管采用哪种方式,起首都要引入异步依靠
  1. <dependency>
  2.     <groupId>com.lmax</groupId>
  3.     <artifactId>disruptor</artifactId>
  4.     <version>3.4.4</version>
  5. </dependency>
复制代码
全局异步
只需在resources下添加log4j2.component.properties,具体内容如下
  1. Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
复制代码

日记输出效果

② 混淆异步配置
起首,我们需要关闭全局异步配置,将上面添加的log4j2.component.properties 内容解释即可
log4j2.xml配置
  1.                 D:/logs<?xml version="1.0" encoding="UTF-8"?>
  2. <Configuration>
  3.     <Appenders>
  4.         <Console name="Console" target="SYSTEM_OUT">
  5.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  6.         </Console>
  7.     </Appenders>
  8.     <Loggers>
  9.         <Root level="INFO">
  10.             <AppenderRef ref="Console"/>
  11.         </Root>
  12.     </Loggers>
  13. </Configuration><?xml version="1.0" encoding="UTF-8"?>
  14. <Configuration>
  15.     <Appenders>
  16.         <Console name="Console" target="SYSTEM_OUT">
  17.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  18.         </Console>
  19.     </Appenders>
  20.     <Loggers>
  21.         <Root level="INFO">
  22.             <AppenderRef ref="Console"/>
  23.         </Root>
  24.     </Loggers>
  25. </Configuration><?xml version="1.0" encoding="UTF-8"?>
  26. <Configuration>
  27.     <Appenders>
  28.         <Console name="Console" target="SYSTEM_OUT">
  29.             <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n"/>
  30.         </Console>
  31.     </Appenders>
  32.     <Loggers>
  33.         <Root level="INFO">
  34.             <AppenderRef ref="Console"/>
  35.         </Root>
  36.     </Loggers>
  37. </Configuration><appender name="async" >
  38.     <appender-ref ref="console" />
  39. </appender>
  40. <root level="ALL">
  41.    
  42.     <appender-ref ref="console" />
  43.    
  44.     <appender-ref ref="async" />        
  45. </root>   
复制代码
输出效果:

注意事项:
九、阿里巴巴日记规约

通过上面八小节我们对Java日记框架应该非常熟悉了,并且也知道怎么使用了。但在日记开发中,使用日记照旧有写规约需要我们去遵守。
下面式阿里巴巴Java开发手册中的日记规约
❶【强制】应用中不可直接使用日记系统(Log4j、Logback)中的 API,而应依靠使用日记框架(SLF4J、JCL--Jakarta Commons Logging)中的 API,使用门面模式的日记框架,有利于维护和各个类的日记处置惩罚方式统一。
说明:日记框架(SLF4J、JCL--Jakarta Commons Logging)的使用方式(推荐使用 SLF4J)
1)使用SLF4J
  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. private static final Logger logger = LoggerFactory.getLogger(Test.class);
复制代码
  1. import org.apache.commons.logging.Log;
  2. import org.apache.commons.logging.LogFactory;
  3. private static final Log log = LogFactory.getLog(Test.class);
复制代码
❷【强制】所有日记文件至少生存 15 天,因为有些异常具备以“周”为频次发生的特点。对于当天日记,以“应用名.log”来生存,
生存在”/home/admin/应用名/logs/“目录下,过往日记格式为: {logname}.log.{生存日期},日期格式:yyyy-MM-dd
正例:以 aap 应用为例,日记生存在/home/admin/aapserver/logs/aap.log,历史日记名称为aap.log.2021-03-23
❸【强制】根据国家法律,网络运行状态、网络安全变乱、个人敏感信息操作等相关记录,留存的日记不少于六个月,并且进行网络多机备份。
❹【强制】应用中的扩展日记(如打点、暂时监控、访问日记等)定名方式:appName_logType_logName.log。
说明:推荐对日记进行分类,如将错误日记和业务日记分开存放,便于开发人员检察,也便于通过日记对系统进行实时监控。
正例:mppserver 应用中单独监控时区转换异常,如:
mppserver_monitor_timeZoneConvert.log
❺ 【强制】在日记输出时,字符串变量之间的拼接使用占位符的方式。
说明:因为 String 字符串的拼接会使用 StringBuilder 的append()方式,有肯定的性能消耗。使用占位符仅是更换动作,可以有效提拔性能。
正例:
  1. logger.debug("Processing trade with id: {} and symbol: {}", id, symbol);
复制代码
❻【强制】对于 trace/debug/info 级别的日记输出,必须进行日记级别的开关判定。
说明:虽然在 debug(参数)的方法体内第一行代码 isDisabled(Level.DEBUG_INT)为真时(Slf4j 的常见实现Log4j 和 Logback),就直接 return,但是参数大概会进行字符串拼接运算。此外,如果 debug(getName())这种参数内有 getName() 方法调用,无谓浪费方法调用的开销。
正例:
  1. // 如果判断为真,那么可以输出 trace 和 debug 级别的日志
  2. if (logger.isDebugEnabled()) {
  3.     logger.debug("Current ID is: {} and name is: {}", id, getName());
  4. }
复制代码
❼【强制】避免重复打印日记,浪费磁盘空间,务必在日记配置文件中设置 additivity=false。
正例:
  1. [/code]❽ 【强制】生产情况禁止直接使用 System.out 或 System.err 输出日记或使用e.printStackTrace() 打印异常堆栈 。
  2. [indent]说明:标准日记输出与标准错误输出文件每次Jboss重启时才滚动,如果大量输出送往这两个文件,轻易造成文件大小超过操作系统大小限定。
  3. [/indent]❾ 【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处置惩罚,那么通过关键字 throws 往上抛出。
  4. [b]正例:[/b]
  5. [code]logger.error("inputParams:{} and errorMessage:{}", 各类参数或者对象 toString(), e.getMessage(), e);
复制代码
❿ 【强制】日记打印时禁止直接用 JSON 工具将对象转换成 String。
说明:如果对象里某些 get 方法被覆写,存在抛出异常的情况,则大概会因为打印日记而影响正常业务流程的执行。
正例:
打印日记时仅打印出业务相关属性值大概调用其对象的 toString() 方法。
⓫ 【推荐】谨慎地记录日记。生产情况禁止输出 debug 日记;有选择地输出 info 日记;
如果使用 warn 来记录刚上线时的业务举动信息,肯定要注意日记输出量的题目,避免把服务器磁盘撑爆,并记得实时删除这些观察日记。
说明:大量地输出无效日记,不利于系统性能提拔,也不利于快速定位错误点。记录日记时请思考:这些日记真的有人看吗?看到这条日记你能做什么?能不能给题目排查带来好处?
⓬ 【推荐】可以使用 warn 日记级别来记任命户输入参数错误的情况,避免用户投诉时,无所适从。
说明:如非必要,请不要在此场景打出 error 级别,避免频繁报警。 注意日记输出的级别,error 级别只记录系统逻辑出错、异常大概紧张的错误信息。
⓭ 【推荐】尽量用英文来描述日记错误信息,如果日记中的错误信息用英文描述不清楚的话使用中文描述即可,否则轻易产生歧义。
说明:国际化团队或海外摆设的服务器由于字符集题目,使用全英文来解释和描述日记错误信息。
本期内容到这儿就结束了 ★,°:.☆( ̄▽ ̄)/$:.°★ 。  希望对您有所资助
我们下期再见  ヾ(•ω•`)o   (●'◡'●)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4