Java日志体系

日志

Java体系日志很多,一直没有整理,乱乱的。好,我们先来看看日志框架组件以及大致处理流程:

  • Loggers:Logger负责捕捉事件并将其发送给合适的Appender
  • Appenders:也称为Handlers,负责从Logger中取出日志消息,并使用Layout来格式化消息,然后将消息发送出去,比如发送到控制台、文件或其他日志收集系统。
  • Layouts:也称为Formatters,负责对日志事件进中的数据进行转换和格式化。
  • Filters:过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过。

框架

  • log4j(最早的Java领域日志,作者Ceki Gülcü,现归属Apache)
  • jul(jdk1.4后新增,看到log4j后加的)
  • logback(log4j作者Ceki Gülcü另外一个框架)
  • log4j2(log4j的改良版本,Apache)

门面

  • jcl(Apache 推出 Jakarta Commons Logging)
  • slf4j(log4j作者Ceki Gülcü写的,和logback一起出现的)

时间轴

在这里插入图片描述

使用

log4j

log4j 1.x 版本,2015年5月,Apache宣布log4j1.x 停止更新。最新版为1.2.17。

  • 依赖
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>
  • classpath下配置log4j.properties
### 日志记录器Logger的全局设置 ###
#第一个参数指定输出的最低日志级别,即只输出该级别及以上级别的日志,D和E为自定义名字,对应下面appender
log4j.rootLogger=DEBUG,stdout,D,E

#*******设置控制台输出********
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#指定标准输出设备为系统输出设备
log4j.appender.stdout.Target=System.out
#指定使用自定义的格式化器
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#指定日志格式
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n


#********文件输出每天一个文件********
log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
#指定将日志输出到哪个文件中
log4j.appender.D.File=./debug.log
#指定文件写入方式为追加
log4j.appender.D.Append=true
#指定最低输出级别,针对这个appender
log4j.appender.D.Threshold=DEBUG
log4j.appender.D.DatePattern='.'yyyy-MM-dd-HH-mm
#指定日志格式
log4j.appender.D.layout=org.apache.log4j.SimpleLayout

#********文件输出按照大小来生产文件********
log4j.appender.E=org.apache.log4j.RollingFileAppender
log4j.appender.E.File=./error.log
log4j.appender.E.Append=true
#指定最低输出级别,针对这个appender
log4j.appender.E.Threshold=ERROR
#指定日志文件的最大尺寸
log4j.appender.E.MaxFileSize=20KB
#指定最大备份数为5
log4j.appender.E.MaxBackupIndex=5
#指定日志输出格式使用自定义格式
log4j.appender.E.layout=org.apache.log4j.PatternLayout
#指定日志格式
log4j.appender.E.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

#********指定具体包打印日志级别********
log4j.logger.org.mybatis=DEBUG,D
  • appender
全路径备注
org.apache.log4j.ConsoleAppender控制台
org.apache.log4j.FileAppender文件
org.apache.log4j.DailyRollingFileAppender每天产生一个日志文件
org.apache.log4j.RollingFileAppender文件大小到达指定尺寸的时候产生一个新的文件
org.apache.log4j.WriterAppender将日志信息以流格式发送到任意指定的地方
  • 属性配置

不同的appender有的属性不同,动手点到类里瞧瞧。例如RollingFileAppender的 File、Append、Threshold等。

  • 伪Java 代码
import org.apache.log4j.Logger;
// 获取logger
 Logger logger = Logger.getLogger(App.class.getName());
 logger.error("11111");

log4j2

2.x版本配置文件后缀,只能为".xml",".json"或者".jsn"。一般建议log4j2使用xml形式配置。默认没有配置文件情况,也会输出error以上级别的日志到控制台。

  • 依赖
 <dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-api</artifactId>
   <version>2.7</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.7</version>
</dependency>
  • classpath下配置log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN" monitorInterval="30">
    <!--先定义所有的appender-->
    <appenders>
        
        <!--这个输出控制台的配置-->
        <console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
        </console>
        
        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
        <File name="log" fileName="log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>
        
        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"
                     filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log"
                     filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>

        <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"
                     filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效,也就是说打印的日志内容会到相应文件中-->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息,可以作为定义具体包日志级别-->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <root level="all">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>
</configuration>
  • 配置详解

    节点不区分大小写,试验过。

1.根节点Configuration有两个属性:statusmonitorinterval,有两个子节点:AppendersLoggers(表明可以定义多个AppenderLogger):

  • status用来指定log4j本身的打印日志的级别。
  • monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s

2.Appenders节点,常见的有三种子节点:ConsoleRollingFileFile

  • Console节点用来定义输出到控制台的Appender
    (1)name:指定 Appender 的名字
    (2)targetSYSTEM_OUTSYSTEM_ERR,一般只设置默认:SYSTEM_OUT
    (3)PatternLayout:输出格式,不设置默认为%m%n
  • File节点用来定义输出到指定位置的文件的Appender
    (1)name:指定Appender的名字
    (2)fileName:指定输出日志的目的文件带全路径的文件名
    (3)PatternLayout:输出格式,不设置默认为%m%n
  • RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender
    (1)name:指定Appender的名字
    (2)fileName:指定输出日志的目的文件带全路径的文件名
    (3)PatternLayout:输出格式,不设置默认为%m%n
    (4)filePattern:指定新建日志文件的名称格式
    (5)Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志
    (6)TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hourmodulate=true用来调整时间:比如现在是早上3aminterval是4,那么第一次滚动是在4am,接着是8am12am…而不是7am
    (7)SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size 属性用来定义每个日志文件的大小.
    (8)DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。

3.Loggers节点,常见的有两种RootLogger
Root 节点用来指定项目的根日志,如果没有单独指定 Logger,那么就会默认使用该 Root日志输出
  level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF
  AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender
Logger 节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
  level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF
  name:用来指定该 Logger所适用的类或者类所在的包全路径,继承自 Root节点.
  AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自 Root。如果指定了,那么会在指定的这个AppenderRootAppender中都会输出,此时我们可以设置 Loggeradditivity="false"只在自定义的 Appender中进行输出。

  1. 关于日志 level
    共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF
  • All:最低等级的,用于打开所有日志记录.
  • Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出.
  • Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.
  • Info:消息在粗粒度级别上突出强调应用程序的运行过程.
  • Warn:输出警告及warn以下级别的日志.
  • Error:输出错误信息日志.
  • Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志.
  • OFF:最高等级的,用于关闭所有日志记录.
    程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。

log4j和log4j2 日志级别有8个:按照从低到高为:All(打开所有日志级别)< Trace < Debug < Info < Warn < Error < Fatal < OFF(关闭所有日志级别)

JUL

JDK 1.4 之后自带的log,位于java.util.logging包下。它使用起来也是很简单,不需要依赖额外的jar。

  • 日志级别

​ FINEST(最低值)–>FINER–>FINE–>CONFIG–>INFO(默认级别)–>WARNING–>SEVERE(最高值)

  • 默认配置

    $JAVA_HOME/jre/lib/logging.properties

############################################################
#       Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#       Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across

# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
#     <level>: <log message> [<date/time>]
#
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
  • 自定义配置
#配置RootLogger的Handler,有java.util.logging.ConsoleHandler,java.util.logging.FileHandler
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler

#针对所有handler与包的根日志级别
.level= ALL

#文件位置,可以是任何path,这样配置默认在项目根路径下
java.util.logging.FileHandler.pattern = java%u.log
#默认一个文件最多50000条日志记录
java.util.logging.FileHandler.limit = 50000
#设置FileHandle的日志级别为WARNING(低于这个级别就不打印到文件里)
java.util.logging.FileHandler.level= WARNING
#配置生成一个文件
java.util.logging.FileHandler.count = 1
#配置使用SimpleFormatter格式器
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
#配置追加模式
java.util.logging.FileHandler.append=true



#ConsoleHandler的日志级别默认是INFO(低于这个级别就不打印到控制台)
java.util.logging.ConsoleHandler.level = INFO
#ConsoleHandler的默认格式化器时SimpleFormatter
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter


#设置日志格式
java.util.logging.SimpleFormatter.format= %1$tc %2$s%n%4$s: %5$s%6$s%n
  • 加载配置文件
public class JULLogConfig {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("${file.path}/logging.properties");
        LogManager manager = LogManager.getLogManager();
        manager.readConfiguration(inputStream);
        Logger logger = Logger.getLogger(JULLogConfig.class.getName());
      // 高于设置的WARNING级别,因此会打印到log文件里
        logger.severe("999999999");
    }
}

logback

  • logbacklog4j是一个人写的
  • springboot默认使用的日志框架是logback
  • 三个模块组成
    • logback-core
    • logback-classic
    • logback-access
  • 其他的关于性能,关于内存占用,关于测试,关于文档详见源码及官网说明

logback-core 是其它模块的基础设施,其它模块基于它构建,显然,logback-core 提供了一些关键的通用机制。logback-classic 的地位和作用等同于 Log4J,它也被认为是 Log4J 的一个改进版,并且它实现了简单日志门面 SLF4J;而 logback-access 主要作为一个与 Servlet 容器交互的模块,比如说tomcat或者 jetty,提供一些与 HTTP 访问相关的功能。

  • 依赖
 <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
  • 配置文件logback.xml
<configuration>
    <!-- 属性文件:在properties文件中找到对应的配置项 -->
    <springProperty scope="context" name="logging.path"  source="logging.path"/>
    <springProperty scope="context" name="logging.level" source="logging.level.com.astilt.spring.boot"/>
    <!-- 默认的控制台日志输出,一般生产环境都是后台启动,这个没太大作用 -->
    <appender name="STDOUT"  class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n</Pattern>
        </encoder>
    </appender>

    <appender name="logFile"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
      <!--临界值过滤器,过滤掉低于指定临界值的日志-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>${logging.level}</level>
        </filter>
      <!--指定被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值-->
        <file>
            ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log
        </file>
       <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-loggerone.log.%d{yyyy-MM-dd}</FileNamePattern>
           <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
     <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
  
  
 <!-- com.astilt.controller这个包下的${logging.level}级别的日志将会使用logFile来打印-->
 <logger name="com.astilt.controller" level="${logging.level}"
        additivity="false">
    <appender-ref ref="logFile" />
</logger>

  
<root level="${logging.level}">
    <appender-ref ref="STDOUT"/>
</root>

</configuration>

xml的节点:

<configuration scan="true" scanPeriod="60 seconds" debug="false">  
    <property name="glmapper-name" value="glmapper-demo" /> 
    <contextName>${glmapper-name}</contextName> 
    
    <appender>
        //xxxx
    </appender>   
<!-- 用来设置某一个包或者具体的某一个类的日志打印级别以及指定appender。-->
    <logger>
        //xxxx
    </logger>
    
    <root>             
       //xxxx
    </root>  
</configuration>  

scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。

scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。

debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。

  • 节点

    root:根logger,也是logger

    logger:普通的logger

    appender:需要被 logger或者rootappender-ref指向,它种类有

    • ConsoleAppender:把日志添加到控制台
    • FileAppender:把日志添加到文件
    • RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。它是FileAppender的子类

JCL

Jakarta Commons-logging(JCL)是Apache 最早提供的日志的框架接口。它本身并没有记录log的功能,只是统一了JDK Logging与Log4j的AP。

动态查找原理:Log 是一个接口声明。LogFactory 的内部会去装载具体的日志系统,并获得实现该Log 接口的实现类。LogFactory 内部装载日志系统的流程如下:

  1. 首先,寻找org.apache.commons.logging.LogFactory 属性配置。
  2. 否则,利用JDK1.3 开始提供的service 发现机制,会扫描classpah 下的META-INF/services/org.apache.commons.logging.LogFactory文件,若找到则装载里面的配置,使用里面的配置。
  3. 否则,从Classpath 里寻找commons-logging.properties ,找到则根据里面的配置加载。
  4. 否则,使用默认的配置:如果能找到Log4j 则默认使用log4j 实现,如果没有则使用JDK14Logger 实现,再没有则使用commons-logging 内部提供的SimpleLog 实现。
  • 依赖
 <dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.2</version>
</dependency>
<!-- 我是用是log4j-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>     
  • 伪Java 代码
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 Log logger = LogFactory.getLog(App.class);
 logger.info("111111");
  • log4j.properties 如上,不列了。

Slf4J

The Simple Logging Facade for Java(SLF4J)可作为各种日志记录框架(例如java.util.logging,logback和log4j)的简单外观或抽象。

说白了就是提供统一接口,实现由各个具体的日志框架实现。目前支持的日志框架有:

  • slf4j-log4j12-1.7.28.jar (log4j 1.2.x 版本)+log4j
  • slf4j-jdk14-1.7.28.jar(JDK 1.4日志记录)
  • slf4j-nop-1.7.28.jar
  • slf4j-simple-1.7.28.jar
  • slf4j-jcl-1.7.28.jar
  • logback-classic-1.2.3.jar 、logback-core-1.2.3.jar

按需添加自己使用的日志jar。并加上对应的日志配置文件。

使用的伪Java代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Logger logger = LoggerFactory.getLogger(App.class);
logger.error("11111");

在SprngBoot中自带了slf4j+logback,不需要导入包,开箱即用,也是我平时使用最多的方式。

在使用层面,我觉得log4j、logback最方便,配置和概念都比较清晰,也比较相像。至于JUL、log4j2 使用的比较少,JCL也不多,目前基本上slf4j+logback可以畅行江湖,推荐!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值