使用Slf4j集成Log4j2构建项目日志系统的完美解决方案
一、背景
最近因为公司项目性能需要,我们考虑把以前基于的log4j的日志系统重构成基于Slf4j和log4j2的日志系统,因为,使用slf4j可以很好的保证我们的日志系统具有良好的兼容性,兼容当前常见几种日志系统,而使用log4j2而不是log4j是因为Log4j 1.x 在高并发情况下出现死锁导致cpu使用率异常飙升,而Log4j2.0基于LMAX Disruptor的异步日志在多线程环境下性能会远远优于Log4j 1.x和logback(官方数据是10倍以上)。
关于slf4j的原理以及优点,请参见我的另一篇博客:slf4j介绍以及实现原理窥探
二、搭建步骤
1.依赖管理
1).删除项目中存在的Log4j1.x所必须的log4j和slf4j-log4j12等依赖。
可以到项目的根目录,执行:mvn dependency:tree > tree.log,之后使用 cat tree.log | grep log4j命令进行查找。
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
2).添加以下slf4j和log4j2的依赖.
<!-- slf4j核心包-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.13</version>
<scope>runtime</scope>
</dependency> <!--核心log4j2jar包-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.4.1</version>
</dependency>
<!--用于与slf4j保持桥接-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.4.1</version>
</dependency>
<!--web工程需要包含log4j-web,非web工程不需要-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.4.1</version>
<scope>runtime</scope>
</dependency> <!--需要使用log4j2的AsyncLogger需要包含disruptor-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.2.0</version>
</dependency>
2.web.xml中设置log4j2的监听器和过滤器(servlet3.0及以上版本不需要该步操作)
<!--对于log4j2,Servlet2.5以前的版本需要-->
<listener>
<listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener>
<filter>
<filter-name>log4jServletFilter</filter-name>
<filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>log4jServletFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
注意:log4j2不再支持properties文件了,只支持xml,json或是yaml,不指定位置的情况下默认在src/main/resources下查找。
如果需要自定义位置,需要在上面的web.xml中添加以下代码
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>/WEB-INF/classes/log4j2.xml</param-value>
</context-param>
3.log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="off" monitorInterval="1800">
<properties>
<property name="LOG_HOME">/opt/logs/hafiz/log4j2Demo/logs</property>
<property name="ERROR_LOG_FILE_NAME">error</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p (%F:%L) - %m%n" />
</Console>
<RollingRandomAccessFile name="ErrorLog"
fileName="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log"
filePattern="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log.%d{yyyy-MM-dd}.gz">
<PatternLayout
pattern="%d %-5p (%F:%L) - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<!-- 3rdparty Loggers -->
<logger name="org.springframework.core" level="info">
</logger>
<logger name="org.springframework.beans" level="info">
</logger>
<logger name="org.springframework.context" level="info">
</logger>
<logger name="org.springframework.web" level="info">
</logger>
<logger name="com.hafiz.www.controller" level="error" includeLocation="true" additivity="false">
<appender-ref ref="ErrorLog"/>
<appender-ref ref="Console"/>
</logger>
<root level="info" includeLocation="true">
<appender-ref ref="Console"/>
</root>
</Loggers>
</Configuration>
4.测试类UserController.java
package com.hafiz.www.controller; import com.hafiz.www.po.UserEntity;
import com.hafiz.www.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody; import java.util.ArrayList;
import java.util.List; /**
* Desc:用户信息控制器
* Created by hafiz.zhang on 2016/8/27.
*/
@Controller
@RequestMapping("/user")
public class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired
private UserService userService; @RequestMapping(value = "/all", method = RequestMethod.GET)
@ResponseBody
public List<UserEntity> getAllUsers(){
logger.info("[GET] /user/all getAllUsers");
List<UserEntity> list = userService.getAllUsers();
logger.debug("This is log of level of debug");
logger.trace("log4j2 Demo");
logger.error("哎呀,出错啦~");
return list;
}
}
注意:在JVM启动参数中增加 -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector 开启异步日志.
三、小问题:
项目不打印日志并且报:SLF4J: Class path contains multiple SLF4J bindings.主要问题在于在项目中既存在slf4j-log4j12的jar包又存在log4j-slf4j-impl的jar包,导致出现了两个打印日志实现类,所以slf4j门面不知道具体应该使用哪一个进行输出日志,所以导致不打印日志。
因为我之前是log4j 1.x,并且我在web.xml里面指定了log4j.properties文件的位置,第一次运行项目,忘了修改其值为log4j2.xml,出现了"Context [] startup failed due to previous errors"的错误,导致项目启动不起来,web.xml中修改为如下方式以后就正常了。
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>/WEB-INF/classes/log4j2.xml</param-value>
</context-param>
使用Slf4j集成Log4j2构建项目日志系统的完美解决方案的更多相关文章
- java项目日志系统的总结
目录 日志系统归类以及关系 日志的三个组件 slf4j的使用 项目中构建日志系统 使用例子 日志系统归类以及关系 常用的日志框架: slf4j.logback .log4j.log4j2.JUL(ja ...
- 【ELK】5.spring boot日志集成ELK,搭建日志系统
阅读前必看: ELK在docker下搭建步骤 spring boot集成es,CRUD操作完整版 ============================================== 本章集成 ...
- springboot2.7.x 集成log4j2配置写入日志到mysql自定义表格
在阅读之前请先查看[springboot集成log4j2] 本文暂不考虑抽象等实现方式,只限于展示如何自定义配置log4j2并写入mysql数据库(自定义结构) 先看下log4j2的配置 <?x ...
- 利用开源架构ELK构建分布式日志系统
问题导读 1.ELK产生的背景?2.ELK的基本组成模块以及各个模块的作用?3.ELK的使用总计有哪些? 背景 日志,对每个系统来说,都是很重要,又很容易被忽视的部分.日志里记录了程序执行的关键信息, ...
- 记一次项目上线后Log4j2不输出日志的坑
公司项目采用了Log4j2来输出日志,在开发环境和测试环境下均可以输出日志,但在生成环境就没有日志输出.开始毫无头绪,后来通过不断的排查,终于解决了这个问题.在此记录下该问题的解决过程,便于后 ...
- 6 个 K8s 日志系统建设中的典型问题,你遇到过几个?
作者 | 元乙 阿里云日志服务数据采集客户端负责人,目前采集客户端 logtail 在集团百万规模部署,每天采集上万应用数 PB 数据,经历多次双 11.双 12 考验. 导读:随着 K8s 不断 ...
- 使用 SLF4J + LogBack 构建日志系统(转)
转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogB ...
- 常见java日志系统的搭配详解:关于slf4j log4j log4j2 logback jul jcl commons-logging jdk-logging
先看一张图: 是不是有点晕, 晕就对了.这个仅仅是 slf4j 的情况,实际上, 我们不仅要接触到 slf4j ,有时候还会接触其他的日志系统.且看下文分解. 1 直接使用各个日志系统 1.1 直接使 ...
- SLF4J日志系统在项目导入时频现的问题
一.概述 近期在导入一个已有的项目时,日志系统出现了一个问题.错误信息如下: SLF4J问题 SLF4J: Failed to load class "org.slf4j.impl.Stat ...
随机推荐
- Java 抽象类与接口
接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是 Java 语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予 Java 强大的面向对象的能力.他们两者之间对 ...
- nandflash的读写(2440)
说明: 根据物理结构上的区别 , NandFlash主要分为如下两类:1)•SLC (Single Level Cell): 单层式存储2)•MLC (Multi Level Cell): 多层式存储 ...
- 在webapi2中使用OWIN 自寄宿模式
OWIN 自寄宿模式说的直白一点就是不需要IIS了,直接通过路由访问cs模式的服务 敲了一遍官方的例子,首先安装Microsoft.AspNet.WebApi.OwinSelfHost,注意不要安装 ...
- wamp 修改默认apache 80端口
wamp server 环境安装包 修改默认80端口 D:\wamp\bin\apache\apache2.4.9\conf\httpd.conf 找到如下代码出修改后,重启apache即可 ## L ...
- python 类定义 继承
0 前言 系统:win7 64bit IDE : python(x,y) 2.7.6.1 IDE集成的解释器:Python 2.7.6 (default, Nov 10 2013, 19:24:18) ...
- [Asp.net]常见word,excel,ppt,pdf在线预览方案,有图有真相,总有一款适合你!
引言 之前项目需要,查找了office文档在线预览的解决方案,顺便记录一下,方便以后查询. 方案一 直接在浏览器中打开Office文档在页面上的链接.会弹出如下窗口: 优点:主流浏览器都支持. 缺点: ...
- Java基础——继承、接口
一个对象变量(例如,变量e)可以引用多种实际类型的现象被称为多态(polymorphism). 在运行时能够自动地选择调用哪个方法的现象称为动态绑定(dynamic binding). 在Java程序 ...
- ClassNotFoundException: org.apache.catalina.loader.DevLoader 自己摸索,丰衣足食
使用tomcat插件时遇到的问题: ClassNotFoundException: org.apache.catalina.loader.DevLoader 解决方案: 参考了许多文章,对我自己的目录 ...
- KALI Linux problems & Study Red Hat | Ubuntu
Problem When you ask some website with https head.you may met the problem secure connection failed ...
- jq 根据值的正负变色
效果图这样: 意思就是根据最后的百分值变色,值为负变绿色,值为正变红色. 所以只要取到那个标签里的值了,就能根据正负的判断决定颜色. 我的html部分这样: /*不过他们都说我的dom结构不太合理,同 ...