• Java日志


    日志

    市场上存在非常多的日志框架。如下是常见的日志框架及其相关历史

    • 日志门面(Facade):所谓门面更底层一点说就是接口,所以在工程中可以通过门面接入不同的日志系统
      • JCL(Apache Commons Logging):是Apache的一个日志框架,由于是Jakarta小组写的所以命名为JCL,但是最近的一次更新也是在2014年,所以太老了,不推荐使用
      • jboss-logging:使用的场景太少了,不适合使用
      • SLF4j:这个就是为各种loging APIs提供一个简单统一的接口
    • 日志框架(具体实现)
      • Log4j:首次出来,使用状况还不错,但是存在性能问题,所以作者准备升级一下
      • Logback:Log4j的作者觉得重写框架可能太费时间,于是重新写了一个,这就是日志实现
      • Log4j2:是Apache所写的,但是写的太好,许多框架并不适配它
      • JUL(java.util.logging):java自己的日志框架

    image-20210127141100382

    slf4j-api、slf4j-log4j12以及log4j之间的关系

    1、slf4j-api :为java提供的简单日志门面,定义了众多接口。他不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。

    在编译时 slf4j-api 中的 LoggerFactor 类的private final static void bind() 方法会寻找具体的日志实现类绑定主要通过StaticLoggerBinder.getSingleton()

    2、slf4j-log4j12

    他是链接 slf4j-api 和 log4j 中间的适配器。它实现了 slf4j-api 中 StaticLoggerBinder 接口,从而使得在编译时绑定的是slf4j-log4j12的getSingleton()方法

    3、log4j

    这个是具体的日志系统。通过slf4j-log4j12初始化Log4j,达到最终日志的输出。

    image-20210127142200807

    SLF4j的使用

    SLF4j官网

    以后开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法;

    给系统里面导入slf4j的jar和 logback的实现jar

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class HelloWorld {
        public static void main(String[] args) {
            Logger logger = LoggerFactory.getLogger(HelloWorld.class);
            logger.info("Hello World");
        }
    }
    

    下图是不同的日志实现统一使用 slf4j 所需要的jar包及其关系

    concrete-bindings

    每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件;

    日志框架冲突问题

    因为不同框架所使用的日志实现各不相同,共处于一个项目中有时会产生问题

    • spring-boot-starter-logging(slf4j+logback):

    • Spring(commons-logging)

    • Hibernate(jboss-logging)

    • MyBatis...

    如何统一日志记录,使不同的框架统一使用slf4j进行输出?

    legacy

    如何让系统中所有的日志都统一到slf4j;

    1、将系统中其他日志框架先排除出去;

    2、用中间包来替换原有的日志框架;

    3、我们导入slf4j其他的实现

    输出格式

    log4j日志输出格式一览

    • %c 输出日志信息所属的类的全名
    • %logger{20} 限定所属类的全名长度为20
    • %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH:mm:ss },输出类似:2002-10-18- 22:10:28
    • %f 输出日志信息所属的类的类名
    • %l / %line 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行
    • %m / %msg 输出代码中指定的信息,如log(message)中的message
    • %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
    • %p / %level 输出级别,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,依此类推
    • %r 输出自应用启动到输出该日志信息所耗费的毫秒数
    • %t / %thread 输出产生该日志事件的线程名
    • %method 所在的方法

    %5p [%t] (%F:%L) - %m%n 就表示:宽度是5的优先等级 线程名称 (文件名:行号) - 信息 回车换行

    image-20200630202052005

    log4j.properties

    log4j.rootLogger=debug, stdout, R
     
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
     
    log4j.appender.R=org.apache.log4j.RollingFileAppender
    log4j.appender.R.File=example.log
    log4j.appender.R.MaxFileSize=100KB
    log4j.appender.R.MaxBackupIndex=5
    log4j.appender.R.layout=org.apache.log4j.PatternLayout
    log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
    

    释意

    设置日志输出的等级为debug,低于debug就不会输出了
    设置日志输出到两种地方,分别叫做 stdoutR

    log4j.rootLogger=debug, stdout, R
    

    第一个地方stdout, 输出到控制台

    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    

    输出格式是 %5p [%t] (%F:%L) - %m%n

    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
    

    第二个地方R, 以滚动的方式输出到文件,文件名是example.log,文件最大100k, 最多滚动5个文件

    log4j.appender.R=org.apache.log4j.RollingFileAppender
    log4j.appender.R.File=example.log
    log4j.appender.R.MaxFileSize=100KB
    log4j.appender.R.MaxBackupIndex=5
    

    输出格式是 %p %t %c - %m%n,在下个步骤讲解

    log4j.appender.R.layout=org.apache.log4j.PatternLayout
    log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
    

    logback.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
      <!-- 日志存放路径 -->
      <property name="log.path" value="E:/Cache/FileStorage/logs"/>
      <!-- 日志输出格式 -->
      <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
    
      <!-- 控制台输出 -->
      <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>${log.pattern}</pattern>
        </encoder>
      </appender>
    
      <!-- 系统日志输出 -->
      <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-info.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <!-- 日志文件名格式 -->
          <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
          <!-- 日志最大的历史 60天 -->
          <maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder>
          <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
          <!-- 过滤的级别 -->
          <level>INFO</level>
          <!-- 匹配时的操作:接收(记录) -->
          <onMatch>ACCEPT</onMatch>
          <!-- 不匹配时的操作:拒绝(不记录) -->
          <onMismatch>DENY</onMismatch>
        </filter>
      </appender>
    
      <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-error.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <!-- 日志文件名格式 -->
          <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
          <!-- 日志最大的历史 60天 -->
          <maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder>
          <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
          <!-- 过滤的级别 -->
          <level>ERROR</level>
          <!-- 匹配时的操作:接收(记录) -->
          <onMatch>ACCEPT</onMatch>
          <!-- 不匹配时的操作:拒绝(不记录) -->
          <onMismatch>DENY</onMismatch>
        </filter>
      </appender>
    
      <!--系统操作日志-->
      <root level="info">
        <appender-ref ref="file_info"/>
        <appender-ref ref="file_error"/>
        <appender-ref ref="console"/>
      </root>
    
      <!-- 系统模块日志级别控制  -->
      <logger name="com.hemou" level="info"/>
      <!-- Spring日志级别控制  -->
      <logger name="org.springframework" level="warn"/>
    
    </configuration>
    
  • 相关阅读:
    实验5
    实验4
    实验3
    《整数计算器》
    《写一个程序,用于分析一个字符串中各个单词出现的频率,并将单词和它出现的频率输出显示》
    《把一个英语句子中的单词次序颠倒后输出》
    个人简介
    学习《构建之法》的感想
    把一个英语句子中的单词次序颠倒后输出。例如输入“how are you”,输出“you are how”;
    写一个程序,用于分析一个字符串中各个单词出现的频率,并将单词和它出现的频率输出显示。(单词之间用空格隔开,如“Hello World My First Unit Test”);
  • 原文地址:https://www.cnblogs.com/hemou/p/13215754.html
Copyright © 2020-2023  润新知