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

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

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

# log4j vs logback
都是日志框架的具体实现

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

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

![201982894650](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160519379-1184094900.png)

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(将日志信息以流格式发送到任意指定的地方)
```

下面是一个示例
![20198289462](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160520755-224790246.png)
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相关日志。
```

spring-boot-starter-logging
org.springframework.boot

```
或者利用利用idea工具排查一下看看相关的日志。
![20198292169](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160521421-2057881974.png)

添加相关log4j依赖

```

org.slf4j
slf4j-log4j12
1.7.28

```

## 配置文件

```
# 表示开启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 可以这样在代码里面打印日志
可以这样的优雅打印日志
![2019829212415](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160522199-2100029807.png)

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

可以注意到这里用的异步的方式在打印日志其实为了让大家看到另外的一个效果
![2019829212553](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160523286-1606650745.png)
OMP-ACTIVITY-THREAD-1 输出的就是线程名字。
当时在配置线程池的时候给线程池配置的名字。这样子在多线程场景下,某一个线程输出的日志一目了然
![2019829212735](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160526879-2131961615.png)
也就说 在多线程的场景下,可以采用配置线程名的方式,这样子就能看到多线程输出端日志了。

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

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

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

## 直接实战
一个工具类
```java
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();
}
}

```

演示效果

![2019829222638](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160529586-878994264.png)

看一下打印的结果

![2019829222728](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160532148-1866943475.png)

可以看到三行日志输出,在同一个线程最后释放后,日志链路id 是没有了。
当然配合常用的一个过滤器,或者aop,就能跟踪到全链路的日志了。
# 更多文章进入
个人网站 [http://www.soulcoder.tech](http://www.soulcoder.tech)
![微信公众号](https://img2018.cnblogs.com/blog/1754610/201908/1754610-20190830160535174-695818797.png)

java日志框架笔记-log4j-springboot整合的更多相关文章

  1. 【SpringBoot】Logback日志框架介绍和SpringBoot整合实战

    ========================11.Logback日志框架介绍和SpringBoot整合实战 2节课================================ 1.新日志框架L ...

  2. 11、Logback日志框架介绍和SpringBoot整合实战 2节课

    1.新日志框架LogBack介绍     简介:日志介绍和新日志框架Logback讲解 1.常用处理java的日志组件 slf4j,log4j,logback,common-logging 等     ...

  3. Java日志框架 (commons-logging,log4j,slf4j,logback)

    转自:http://blog.csdn.net/kobejayandy/article/details/17335407 如果对于commons-loging.log4j.slf4j.LogBack等 ...

  4. Java日志框架Slf4j+Log4j入门

    一.日志系统介绍 slf4j,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统.简答的讲就是slf4j是一系列的日志 ...

  5. 小D课堂 - 零基础入门SpringBoot2.X到实战_第11节 Logback日志框架介绍和SpringBoot整合实战_45、SpringBoot2.x日志讲解和Logback配置实战

    笔记 2.SpringBoot2.x日志讲解和自定义Logback配置实战     简介:讲解SpringBoot2.x整合Logback配置实战 1.官网介绍:https://docs.spring ...

  6. 拨云见日,彻底弄清楚Java日志框架 log4j, logback, slf4j的区别与联系

    log4j 以及 logback, slf4j 官网 日志框架的困惑 作为一个正常的项目,是必须有日志框架的存在的,没有日志,很难追踪一些奇奇怪怪的系统问题. 但是,我们经常在项目的依赖中,见到奇奇怪 ...

  7. Java学习笔记(十九)——Java 日志记录 AND log4j

    [前面的话] 学习的进度应该稍微在快一点. Java日志到了必须学习怎么使用的时候了,因为在项目中要进行使用.基础性文章,选择性阅读. [结构] java日志对调试,记录运行,问题定位都起到了很重要的 ...

  8. Java 日志框架概述(slf4j / log4j / JUL / Common-logging(JCL) / logback)

    一.简介 JAVA日志在初期可能官方并没有提供很好且实用的规范,导致各公司或OSS作者选择自行造轮子,这也导致了目前初学者觉得市面上 Java 日志库繁杂的局面. 现在市面流行以 slf4j(Simp ...

  9. Java日志框架那些事儿

    文章首发于[博客园-陈树义],点击跳转到原文Java日志框架那些事儿. 在项目开发过程中,我们可以通过 debug 查找问题.而在线上环境我们查找问题只能通过打印日志的方式查找问题.因此对于一个项目而 ...

随机推荐

  1. python调用WebService遇到的问题'Document' object has no attribute 'set'

    代码: from suds import WebFault from suds.client import Client url = 'http://******/bns/PtDataSvc.asmx ...

  2. HTML--CSS样式表的基本概念

    CSS(Cascading Style Sheet  叠层样式表) 作用:美化HTML网页 (一)样式表分类 一.内联样式表 和HTML联合显示,控制精准,但是可重用性差,冗余多. 例如:<p ...

  3. 05-k8s调度器、预选策略、优选函数

    目录 k8s调度器.预选策略.优选函数 节点选择过程 调度器 预选策略 优选函数 高级调度设置机制 node选择器/node亲和调度 pod亲和性 污点调度 Taints 与 Tolerations ...

  4. T-SQL 日期

    --日期查询格式 ) --R:06/17/2011 ) --R:2011.06.17 ) --R:17/06/2011 ) --R:17.06.2011 ) --R:17-06-2011 ) --R: ...

  5. 深入学习 Intellij IDEA 调试技巧

    程序员的日常工作除了写代码之外,很大一部分时间将会在查找 BUG,解决问题.查找 BUG,离不开在 IDE 中调试代码.熟练的掌握调试技巧,可以帮助我们减少查找时间,快速定位问题. 在 IDEA 中调 ...

  6. 【iOS】copy 关键字

    以前没注意过 iOS 的 copy, nonatomic, assign, weak, strong 等关键字. 偏偏今天遇到了一个问题,恰恰是关键字的问题,如图: 之前用的是 assign, 没有用 ...

  7. 【Android】error: Error retrieving parent for item: No resource found that matches the given name 'Theme.Sherlock.Light.NoActionBar'.

    问题: res 文件夹下的 values 下的 styles.xml <style name="Sherlock.Light.NoActionBar" parent=&quo ...

  8. Mybatis整合Spring 使用

    1.继承通用的Mapper<T>,必须指定泛型<T> 例如下面的例子: public interface UserInfoMapper extends Mapper<Us ...

  9. leetcode并发题目解题报告JAVA版

    一.Print in Order Suppose we have a class: public class Foo { public void first() { print("first ...

  10. 分布式ID系列(2)——UUID适合做分布式ID吗

    UUID的生成策略: UUID的方式能生成一串唯一随机32位长度数据,它是无序的一串数据,按照开放软件基金会(OSF)制定的标准计算,UUID的生成用到了以太网卡地址.纳秒级时间.芯片ID码和许多可能 ...