java日志框架详解-Log4j2
一、概述
Apache Log4j 2 (Log4j – Apache Log4j 2)是对Log4j的升级,它比其前身Log4j 1.x提供了重大改进,并参考了Logback中优秀的设计,同时修复了Logback架构中的一些问题。被誉为是目前最优秀的Java日志框架;企业中通常使用SLF4j门面+Log4j2来记录日志。
Log4j2主要的性能提升:
异常处理:在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
性能提升:log4j2 相较于log4j 和 logback 都具有明显的性能提升,有18倍性能提升,后面会有官方测试的数据。
自动重载配置: 参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。
无垃圾机制: log4j2 在大部分情况下,都可以使用其设计的一套无垃圾机制【对象重用、内存缓冲】,避免频繁的日志收集导致的 jvm gc。

自动重新加载配置
与 Logback 一样,Log4j 2 可以在修改时自动重新加载其配置。与Logback不同,它会这样做 在进行重新配置时不会丢失日志事件。
高级过滤
与 Logback 一样,Log4j 2 支持基于上下文数据、标记、正则表达式和其他组件进行过滤 日志事件。可以指定筛选以在传递到记录器之前或通过时应用于所有事件 追加器。此外,过滤器还可以与记录器相关联。与 Logback 不同,您可以使用通用 Filter 类 在任何这些情况下。
二、Log4j2入门案例
开发实例:
如果您使用启动器来组装依赖项,这意味着您必须排除Logback,然后引入log4j2。
依赖引入POM.xml:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Log4j2配置
log4j2默认加载classpath下的 log4j2.xml 文件中的配置。
<?xml version="1.0" encoding="UTF-8"?><!--status : 这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,会看到log4j2内部各种详细输出monitorInterval : Log4j能够自动检测修改配置文件和重新配置本身, 设置间隔秒数。此处表示每隔600秒重读一次配置文件
-->
<Configuration status="OFF" monitorInterval="600"><!--日志级别:TRACE < DEBUG < INFO < WARN < ERROR < FATAL--><!--如果设置为WARN,则低于WARN的信息都不会输出--><Properties><!-- 配置日志文件输出目录,此处为项目根目录下的logs文件夹 --><Property name="LOG_HOME">/app/applogs</Property><!-- 配置日志文件名称前缀 --><Property name="LOG_FILE_NAME">cu-upcc-ccc1-provider</Property><!-- 配置输出日志级别-通用日志 --><Property name="LOG_LEVEL">INFO</Property><!-- 配置输出日志级别-重要日志1 --><Property name="LOG_LEVEL_V1">DEBUG</Property><!-- 配置日志输出源appender的名称 --><Property name="APPENDER_NAME">APP-PROVIDER</Property><!-- 配置子Logger是否继承父Logger的输出源,true-是,false-否,默认true --><Property name="LOGGER_ADDITIVITY">true</Property><!-- 触发日志文件分割的时间间隔,此配置必须和filePattern协调, 如果后者是精确到HH, 则此配置项单位是小时,若后者精确到dd, 则此配置项单位是天--><Property name="POLICY_TIME_BASED_INTERVAL">1</Property><!-- 日志清理规则 从basePath起清理日志文件的目录层级深度 --><Property name="DELETE_MAX_DEPTH">1</Property><!-- 日志清理规则 文件名称匹配规则 --><Property name="DELETE_IF_FILE_NAME">*.log-*</Property><!-- 日志清理规则 归档日志文件存在时长匹配规则,此配置项必须和filePattern协调, 后者是精确到HH, 这里就要写成xH, xd就不起作用, 另外, 数字最好>2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功! --><Property name="DELETE_IF_LAST_MODIFIED_AGE">24H</Property></Properties><Appenders><!--这个输出控制台的配置--><Console name="Console" target="SYSTEM_OUT"><!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--><ThresholdFilter level="${LOG_LEVEL}" onMatch="ACCEPT" onMismatch="DENY"/><!--日志输出的格式--><PatternLayout pattern="|%d{yyyy-MM-dd HH:mm:ss.SSS}|%5p|%5t|%4c:%L|%X{PtxId}|%X{clientNodeName}|%X{serverNodeName}|%X{clientSysName}|%X{serverSysName}|%X{txId}|%X{logType}|%m|%n" /></Console><RollingRandomAccessFile name="${APPENDER_NAME}" fileName="${LOG_HOME}/${LOG_FILE_NAME}.log"filePattern="${LOG_HOME}/${LOG_FILE_NAME}.log-%d{yyyyMMddHH}"><PatternLayout pattern="|%d{yyyy-MM-dd HH:mm:ss.SSS}|%5p|%5t|%4c:%L|%X{PtxId}|%X{clientNodeName}|%X{serverNodeName}|%X{clientSysName}|%X{serverSysName}|%X{txId}|%X{logType}|%m|%n" /><Policies><TimeBasedTriggeringPolicy interval="${POLICY_TIME_BASED_INTERVAL}"/><!--<SizeBasedTriggeringPolicy size="50MB"/>--></Policies><DefaultRolloverStrategy><Delete basePath="${LOG_HOME}/" maxDepth="${DELETE_MAX_DEPTH}"><IfFileName glob="${DELETE_IF_FILE_NAME}" /><!--!Note: 这里的age必须和filePattern协调, 后者是精确到HH, 这里就要写成xH, xd就不起作用另外, 数字最好>2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--><IfLastModified age="${DELETE_IF_LAST_MODIFIED_AGE}" /></Delete></DefaultRolloverStrategy></RollingRandomAccessFile><!-- alarm plugins --><AlarmLog4j2Appender name="AlarmLog4j2Appender" enableApollo="true" apNameSpace="cu-upcc-ccc1-provider"><PatternLayout pattern="|%d{yyyy-MM-dd HH:mm:ss.SSS}|%m" /></AlarmLog4j2Appender></Appenders><!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--><Loggers><Logger name="com.epay.cu1.upcc1.ccc1.provider" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><Logger name="com.epay.ts.lacs.log" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><Logger name="com.epay.ts.piss" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><Logger name="org.springframework" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><Logger name="com.ctrip.framework" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><Logger name="org.apache" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><Logger name="feign.Logger" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><Logger name="com.alibaba.druid" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="${APPENDER_NAME}"/></Logger><logger name="com.broad.assessment.business.dao" level="${LOG_LEVEL_V1}"><AppenderRef ref="${APPENDER_NAME}"/></logger><logger name="org.mybatis" level="${LOG_LEVEL_V1}"><AppenderRef ref="${APPENDER_NAME}"/></logger><logger name="com.unicompayment.basictools" level="${LOG_LEVEL_V1}"><AppenderRef ref="${APPENDER_NAME}"/></logger><!-- alarm plugins --><Logger name="com.epay.cu1.upcc1.ccc1.provider" level="${LOG_LEVEL}" additivity="${LOGGER_ADDITIVITY}"><AppenderRef ref="AlarmLog4j2Appender"/></Logger><Root level="${LOG_LEVEL}"><Appender-Ref ref="Console"/></Root></Loggers></Configuration>
测试代码:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;public class Log4j2Test {private static final Logger logger = LogManager.getLogger();public Log4j2Test(){logger.info( "Hello World!" );}
}
三、Log4j2异步日志
Log4j2提供了两种实现日志的方式,一个是通过AsyncAppender,一个是通过AsyncLogger,分别对应前面我们说的Appender组件和Logger组件。
POM文件异步日志依赖添加:
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.3.4</version>
</dependency>
1、AsyncAppender有锁异步
异步日志是通过引用别的Appender来实现的,当有日志事件到达时,会开启另外一个线程来处理它们。需要注意的是,如果在Appender的时候出现异常,对应用来说是无法感知的。AsyncAppender应该在它引用的Appender之后配置,默认使用java.util.concurrent.ArrayBlockingQueue实现而不需要其它外部的类库。当使用此Appender的时候,在多线程的环境下需要注意,阻塞队列容易受到锁争用的影响,这可能会对性能产生影响。这时候,我们应该考虑使用无锁的异步记录器(AsyncLogger)
日志配置文件
<Configuration status="fatal" monitorInterval="30"><Properties><Property name="myPattern" value="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Properties><Appenders><Console name="ConsoleAppend" target="SYSTEM_OUT"><PatternLayout pattern="${myPattern}"/><!-- 只接受程序中DEBUG级别的日志进行处理--><ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/></Console><!--在Appenders标签内创建Async异步标签--><Async name="AsyncConsoleAppend"><!--指定当前Appenders标签内的哪个Appender需要设置异步并通过引用--><AppenderRef ref="ConsoleAppend"/></Async></Appenders><Loggers><Root level="ALL"><!--设置异步的Appender--><AppenderRef ref="AsyncConsoleAppend"/></Root></Loggers>
</Configuration>
2、AsyncLogger无锁日志
AsyncLogger才是log4j2实现异步最重要的功能体现,也是官方推荐的异步方式。它可以使得调用Logger.log返回的更快。你可以有两种选择:全局异步和混合异步。
全局异步:所有的日志都异步的记录,在配置文件上不用做任何改动,只需要在jvm启动的时候增加一个参数即可实现。
混合异步:你可以在应用中同时使用同步日志和异步日志,这使得日志的配置方式更加灵活。
虽然Log4j2提供以一套异常处理机制,可以覆盖大部分的状态,但是还是会有一小部分的特殊情况是无法完全处理的,比如我们如果是记录审计日志(特殊情况之一),那么官方就推荐使用同步日志的方式,而对于其它一些仅仅是记录一个程序日志的地方,使用异步日志将大幅提升性能,减少对应用本身的影响。混合异步的方式需要通过修改配置文件来实现,使用AsyncLogger标记配置。
全局异步:
<!-- 导入所需的依赖坐标 -->
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.4</version>
</dependency><!-- 在resources资源目录下创建log4j2.component.properties文件并编写配置 -->
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
混合异步:
<Configuration status="fatal" monitorInterval="30"><Properties><Property name="myPattern" value="%d{HH:mm:ss.SSS} [%t] %L %-5level %logger{36} - %msg%n"/></Properties><Appenders><Console name="ConsoleAppend" target="SYSTEM_OUT"><PatternLayout pattern="${myPattern}"/><!-- 只接受程序中DEBUG级别的日志进行处理--><ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/></Console></Appenders><Loggers><!--创建一个自定义的异步Logger--><!--name:对com.xw当前及其子包下的全部类的日志记录走此异步方式--><!--includeLocation:表示去除日志上的行号信息--><!--注:配置多个Logger时需要设置additivty来取消继承RootLogger--><AsyncLoggger name="com.xw" level="INFO" includeLocation="false" additivty="false"><AppenderRef ref="ConsoleAppend"/></AsyncLoggger><!--RootLogger--><Root level="ALL"><!--设置异步的Appender--><AppenderRef ref="ConsoleAppend"/></Root></Loggers>
</Configuration>
相关文章:
java日志框架详解-Log4j2
一、概述 Apache Log4j 2 (Log4j – Apache Log4j 2)是对Log4j的升级,它比其前身Log4j 1.x提供了重大改进,并参考了Logback中优秀的设计,同时修复了Logback架构中的一些问题。被誉为是目前最优秀的Java日志框架&#x…...
C++中vector追加vector
在C中,如果你想将一个vector追加到另一个vector的后面,可以使用std::vector的成员函数insert或者std::copy,或者简单地使用std::vector的push_back方法逐个元素添加。这里我将展示几种常用的方法: 方法1:使用insert方…...
加一(66)
66. 加一 - 力扣(LeetCode) 解法: class Solution { public:vector<int> plusOne(vector<int>& digits) {bool plus_one true;for (int i digits.size() - 1; i > 0; --i) {if (plus_one) {int tmp digits[i] 1;if …...
远程连接-简化登录
vscode通过ssh连接远程服务器免密登录(图文)_vscode ssh-CSDN博客...
canvas的基本用法
canvas canvas元素简介 1.是个container元素<canvas width100 height100></canvas>,有开闭标签 2.有且只有width和height两个attribute,不需要写单位 canvas的基本使用 const canvasEl document.getElementById(canvas01) const ctx …...
Tailwind CSS - Tailwind CSS 引入(安装、初始化、配置、引入、构建、使用 Tailwind CSS)
一、Tailwind CSS 概述 Tailwind CSS 是一个功能优先的 CSS 框架,它提供了大量的实用类(utility classes),允许开发者通过组合这些类来快速构建用户界面 Tailwind CSS 与传统的 CSS 框架不同(例如,Bootstr…...
鸿蒙开发黑科技“stack叠层”替代customdialog
前一篇提到的问题,本篇博文提出了一个解决方案: arkui-x LongPressGesture触发customdialog踩坑记录-CSDN博客 前一段时间遇到的这个问题,通过排除法观察,锁定为customdialog组件有bug,极为容易挂死。不论如何调整使用方法,都还是会触发挂死。 反馈给arkui团队,说是在…...
FreeRTOS从入门到精通 第十五章(事件标志组)
参考教程:【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、事件标志组简介 1、概述 (1)事件标志位是一个“位”,用来表示事件是否发生。 (2)事件标志组是一组事件标志位的集合&#x…...
智慧园区管理平台实现智能整合提升企业运营模式与管理效率
内容概要 在当今数字化的背景下,智慧园区管理平台正逐渐成为企业提升运营效率和管理模式的重要工具。这个平台汇聚了多种先进技术,旨在通过智能整合各类资源与信息,帮助企业实现全面的管理创新。 智慧园区管理平台不仅仅是一个数据处理工具…...
markdown公式特殊字符
个人学习笔记 根号 在 Markdown 中,要表示根号 3,可以使用 LaTeX 语法来实现。常见的有以下两种方式: 行内公式形式:使用一对美元符号 $ 将内容包裹起来,即 $\sqrt{3}$ ,在支持 LaTeX 语法渲染的 Markdow…...
【深度分析】微软全球裁员计划不影响印度地区,将继续增加当地就业机会
当微软的裁员刀锋掠过全球办公室时,班加罗尔的键盘声却愈发密集——这场资本迁徙背后,藏着数字殖民时代最锋利的生存法则。 表面是跨国公司的区域战略调整,实则是全球人才市场的地壳运动。微软一边在硅谷裁撤年薪20万美金的高级工程师&#x…...
学习数据结构(5)单向链表的实现
(1)头部插入 (2)尾部删除 (3)头部删除 (4)查找 (5)在指定位置之前插入节点 (6)在指定位置之后插入节点 (7)删除…...
刷题记录 HOT100回溯算法-5:22. 括号生成
题目:22. 括号生成 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 1: 输入:n 3 输出:["((()))","(()())","(())()",…...
Keepalived高可用集群企业应用实例二
一、实现ipvs的高可用性 ipvs相关配置 虚拟服务器配置结构: virtual_server ip port { …… real_server { …… } real_server { …… } } virtual server (虚拟服务器)的定义格式 virtual_server ip port 定义虚拟主机ip地址及其端口 virtual_server …...
C++计算特定随机操作后序列元素乘积的期望
有一个长度为 n n n的序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an。初始序列的所有元素均为 0 0 0。再给定正整数 m m m、 c c c和 ( n − m 1 ) (n-m1) (n−m1)个正整数 b 1 , b 2 , . . . , b n − m 1 b_1,b_2,...,b_{n-m1} b1,b2,...,bn−m1…...
c++字母大小写转换
可以通过标准库中的 <algorithm> 和 <cctype> 头文件来实现大小写转换。以下是常用的方法: 1. 使用 std::transform 和 std::toupper/std::tolower 1.1 转换为大写 #include <iostream> #include <string> #include <algorithm> //…...
MySQL知识点总结(十六)
请说明在复制拓扑中,中继日志集和从属服务器状态日志的作用。 中继日志用来保存从主服务器接受的二进制日志,与二进制日志相同的格式存储,由服务器自动管理,在其全部内容重放后会自动删除。 从属服务器状态日志存储关于如何连接…...
Windows程序设计10:文件指针及目录的创建与删除
文章目录 前言一、文件指针是什么?二、设置文件指针的位置:随机读写,SetFilePointer函数1.函数说明2.函数实例 三、 目录的创建CreateDirectory四、目录的删除RemoveDirectory总结 前言 Windows程序设计10:文件指针及目录的创建与…...
geolocator包的功能和用法
文章目录 1 概念介绍2 使用方法3 示例代码4 体验分享 我们在上一章回中介绍了如何实现滑动菜单相关的内容,本章回中将介绍如何获取位置信息.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在这里说的获取位置信息本质上是获取当前手机所在位置的…...
Node.js——body-parser、防盗链、路由模块化、express-generator应用生成器
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
