java日志框架笔记log4jspringboot整合

6次阅读

共计 6957 个字符,预计需要花费 18 分钟才能阅读完成。

日志框架 slf4j log4j logback 之间的关系

简答的讲就是 slf4j 是一系列的日志接口,而 log4j logback 是具体实现了的日志框架。

SLF4J 获得 logger 对象:private static final Logger logger = LoggerFactory.getLogger(Test.class); 

log4j vs logback

都是日志框架的具体实现

log4j 是 apache 实现的一个开源日志组件。(Wrapped implementations)

logback 同样是由 log4j 的作者设计完成的,拥有更好的特性,用来取代 log4j 的一个日志框架。是 slf4j 的原生实现。(Native implementations)

logback 是直接实现了 slf4j 的接口,而 log4j 不是对 slf4j 的原生实现,所以 slf4j api 在调用 log4j 时需要一个适配层。
也就是说 logback 实现 slf4j 是不消耗内存和计算开销的。

log4j 配置

log4j 支持两种配置文件格式,一种是 XML 格式的文件,一种是 properties 属性文件。
下面以 properties 属性文件为例介绍 log4j.properties 的配置。

下面开始正式讲解配置

配置 rootLogger

log4j.rootLogger = [level] , appenderName1, appenderName2, …
  • 第一个是日志的输出级别 比如测试环境就可以把 level 换成 DEBUG 级别。
  • appenderName1 表示文件的输出“地方”。这个“地方”需要在下面的配置上继续配置。

这是一个示例,表示开始 DEBUG 级别的日志,然后输出三个日志 file,stdout,trace

log4j.rootLogger=DEBUG,file,stdout,trace

配置日志信息输出目的地 Appender

Log4j 提供的 appender 有以下 5 种,分别可以将日志信息输出到 5 个不同的平台

org.apache.log4j.ConsoleAppender(控制台)org.apache.log4j.FileAppender(文件)org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

下面是一个示例

file 就是那个 AppenderName,第一行的就是上面的几种 appender 的配置,详细的每个 appender 配置看下文

ConsoleAppender

Threshold=WARN:指定日志消息的输出最低层次。ImmediateFlush=true:默认值是 true, 意谓着所有的消息都会被立即输出。Target=System.err:默认情况下是:System.out, 指定输出控制台

FileAppender

Threshold=WARN:指定日志消息的输出最低层次。ImmediateFlush=true:默认值是 true, 意谓着所有的消息都会被立即输出。File=mylog.txt:指定消息输出到 mylog.txt 文件。Append=false:默认值是 true, 即将消息增加到指定文件中,false 指将消息覆盖指定的文件内容。

DailyRollingFileAppender

Threshold=WARN:指定日志消息的输出最低层次。ImmediateFlush=true:默认值是 true, 意谓着所有的消息都会被立即输出。File=mylog.txt:指定消息输出到 mylog.txt 文件。Append=false:默认值是 true, 即将消息增加到指定文件中,false 指将消息覆盖指定的文件内容。DatePattern=”.”yyyy-ww: 每周滚动一次文件,即每周产生一个新的文件。当然也可以指定按月、周、天、时和分。即对应的格式如下:1)”.”yyyy-MM: 每月 
2)”.”yyyy-ww: 每周 
3)”.”yyyy-MM-dd: 每天 
4)”.”yyyy-MM-dd-a: 每天两次 
5)”.”yyyy-MM-dd-HH: 每小时 
6)”.”yyyy-MM-dd-HH-mm: 每分钟

RollingFileAppender

Threshold=WARN:指定日志消息的输出最低层次。ImmediateFlush=true:默认值是 true, 意谓着所有的消息都会被立即输出。File=mylog.txt:指定消息输出到 mylog.txt 文件。Append=false:默认值是 true, 即将消息增加到指定文件中,false 指将消息覆盖指定的文件内容。MaxFileSize=100KB:后缀可以是 KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到 mylog.log.1 文件。MaxBackupIndex=2:指定可以产生的滚动文件的最大数。

配置日志信息的格式(布局)

注意到上面的示例中还有一个配置

log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=${log4j.ConversionPattern}

这是就是布局

Log4j 提供的 layout 有以下几种

org.apache.log4j.HTMLLayout(以 HTML 表格形式布局),org.apache.log4j.PatternLayout(可以灵活地指定布局模式),org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

详细讲一下 PatternLayout 模式
可以在配置文件增加下面这个配置

log4j.ConversionPattern=[account-service]%-d{yyyy-MM-dd HH:mm:ss SS} [%c:%L]-[%p] %m%n

下面是几个参数的结束

- X 号: X 信息输出时左对齐;%p: 输出日志信息优先级,即 DEBUG,INFO,WARN,ERROR,FATAL, 
%d: 输出日志时间点的日期或时间,默认格式为 ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002 年 10 月 18 日 22:10:28,921 
%r: 输出自应用启动到输出该 log 信息耗费的毫秒数 
%c: 输出日志信息所属的类目,通常就是所在类的全名 
%t: 输出产生该日志事件的线程名 
%l: 输出日志事件的发生位置,相当于 %C.%M(%F:%L)的组合, 包括类目名、发生的线程,以及行数。举例:Testlog4.main(TestLog4.java:10) 
%x: 输出和当前线程相关联的 NDC(嵌套诊断环境),尤其用到像 java servlets 这样的多客户多线程的应用中。%%: 输出一个”%”字符 
%F: 输出日志消息产生时所在的文件名称 
%L: 输出代码中的行号 
%m: 输出代码中指定的消息, 产生的日志具体信息 
%n: 输出一个回车换行符,Windows 平台为”\r\n”,Unix 平台为”\n”输出日志信息换行

某个日志太多不想看咋办

log4j 调整某个包的日记级别

比如现在
io.lettuce.core 下面发现很多 DEBUG 的日志
这时候可以在配置文件中加入

log4j.logger.io.lettuce.core=INFO

这就可以把日志级别到 info

来一波独立的业务日志

在一些场景下,想用某些特殊的业务日志记录一些问题,又不想和其他日志混在一起这时候可以采用一些独立日志文件去记录。
配置方式如下:

log4j.logger.traceLogger=INFO,trace

区别于 默认的 log4j.rootLogger。
log4j.logger.name 就是你需要记录的独立日志。

appender 配置如下

log4j.appender.trace=org.apache.log4j.DailyRollingFileAppender
log4j.appender.trace.File=/logs/omp/service/omp-account-service-trace.log
log4j.appender.trace.DatePattern='.'yyyy-MM-dd
log4j.appender.trace.Threshold=INFO
log4j.appender.trace.layout=org.apache.log4j.PatternLayout
log4j.appender.trace.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss.SSS}] - %X{mchId} - %X{mchName}- %m%n
# 不在其他的日志文件输出里面输出
log4j.additivity.traceLogger = false

代码中 使用

private static Logger traceLogger = LoggerFactory.getLogger("traceLogger");

实战 springboot 2.0 整合 log4j

maven

排除任何的 springboot 日志因为这个是 springboot 是自带的 logback 相关日志。

<exclusions>
    <exclusion>
        <artifactId>spring-boot-starter-logging</artifactId>
        <groupId>org.springframework.boot</groupId>
    </exclusion>
</exclusions>

或者利用利用 idea 工具排查一下看看相关的日志。

添加相关 log4j 依赖

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.28</version>
</dependency>

配置文件

# 表示开启 debug 级别  然后配置 三种默认输出,期中 stdout 控制台输出
log4j.rootLogger=DEBUG,file,stdout,err

# 日志输出的格式,详细上文说明
log4j.ConversionPattern=[account-service]%-d{yyyy-MM-dd HH:mm:ss-SS} [%l]-[%t]-[%p] %m%n

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=${log4j.ConversionPattern}

log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=/Applications/log/account-service.log
log4j.appender.file.DatePattern='.'yyyy-MM-dd
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=${log4j.ConversionPattern}

log4j.appender.err=org.apache.log4j.DailyRollingFileAppender
log4j.appender.err.File=/Applications/log/account-service-err.log
log4j.appender.err.DatePattern='.'yyyy-MM-dd
log4j.appender.err.Threshold=ERROR
log4j.appender.err.layout=org.apache.log4j.PatternLayout
log4j.appender.err.layout.ConversionPattern=${log4j.ConversionPattern}

# 自定义的业务日志
log4j.logger.traceLogger=INFO,trace
# 按照文件大小形式分类,没一个 128M 大小一共 40 个
log4j.appender.trace=org.apache.log4j.RollingFileAppender
log4j.appender.trace.File=/Applications/log/account-service-trace.log
log4j.appender.trace.MaxFileSize=128MB
log4j.appender.trace.Append=true
log4j.appender.trace.MaxBackupIndex=40
log4j.appender.trace.Threshold=INFO
log4j.appender.trace.layout=org.apache.log4j.PatternLayout
log4j.appender.trace.layout.ConversionPattern=${log4j.ConversionPattern}

假如拟采用的 lombok 可以这样在代码里面打印日志
可以这样的优雅打印日志

解决多线程 log4j 日志输出混乱的问题,每个线程输出独立的日志

可以注意到这里用的异步的方式在打印日志其实为了让大家看到另外的一个效果

OMP-ACTIVITY-THREAD-1 输出的就是线程名字。
当时在配置线程池的时候给线程池配置的名字。这样子在多线程场景下,某一个线程输出的日志一目了然

也就说 在多线程的场景下,可以采用配置线程名的方式,这样子就能看到多线程输出端日志了。

日志链路追踪

MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能。某些应用程序采用多线程的方式来处理多个用户的请求。在一个用户的使用过程中,可能有多个不同的线程来进行处理。典型的例子是 Web 应用服务器。当用户访问某个页面时,应用服务器可能会创建一个新的线程来处理该请求,也可能从线程池中复用已有的线程。在一个用户的会话存续期间,可能有多个线程处理过该用户的请求。这使得比较难以区分不同用户所对应的日志。当需要追踪某个用户在系统中的相关日志记录时,就会变得很麻烦。

一种解决的办法是采用自定义的日志格式,把用户的信息采用某种方式编码在日志记录中。这种方式的问题在于要求在每个使用日志记录器的类中,都可以访问到用户相关的信息。这样才可能在记录日志时使用。这样的条件通常是比较难以满足的。MDC 的作用是解决这个问题。

MDC 可以看成是一个与当前线程绑定的哈希表,可以往其中添加键值对。MDC 中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。MDC 的内容则由程序在适当的时候保存进去。对于一个 Web 应用来说,通常是在请求被处理的最开始保存这些数据。

直接实战

一个工具类

import java.util.UUID;
import org.apache.log4j.MDC;

public class TraceUtil {public static void traceStart() {String traceId = generateTraceId();
        MDC.put("traceId", traceId);
    }
    public static String getTraceId() {return String.valueOf(MDC.get("traceId"));
    }
    public static void traceEnd() {MDC.clear();
    }
    /**
     * 生成跟踪 ID
     */
    private static String generateTraceId() {return UUID.randomUUID().toString();}
}

演示效果

看一下打印的结果

可以看到三行日志输出,在同一个线程最后释放后, 日志链路 id 是没有了。
当然配合常用的一个过滤器,或者 aop,就能跟踪到全链路的日志了。

更多文章进入

个人网站 [http://www.soulcoder.tech] (http://www.soulcoder.tech)

正文完
 0