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应用生成器
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...

22.Word:小张-经费联审核结算单❗【16】
目录 NO1.2 NO3.4 NO5.6.7 NO8邮件合并 MS搜狗输入法 NO1.2 用ms打开文件,而不是wps❗不然后面都没分布局→页面设置→页面大小→页面方向→上下左右:页边距→页码范围:多页:拼页光标处于→布局→分隔符:分节符…...

Agent 高频知识汇总:查漏补缺参考大全
Agent 高频问题汇总 一、基础概念类 (一)请解释 Agent 的概念及其主要特点 Agent 是一种能够感知所处环境,并基于感知信息做出决策、采取行动以实现特定目标的实体。它既可以是简单的规则基系统,也能是复杂的智能体,…...

本地化部署DeepSeek-R1
本文环境搭建均基于免费工具,感谢开源。 一、下载工具并安装 1. Ollama:最新版本 0.5.7 官网在这里 https://ollama.com/download 但是下载太慢,得换个思路 https://sourceforge.net/projects/ollama.mirror/ 2.Chatbox https://cha…...

验证二叉搜索数(98)
98. 验证二叉搜索树 - 力扣(LeetCode) 解法: /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* …...

StarRocks BE源码编译、CLion高亮跳转方法
阅读SR BE源码时,很多类的引用位置爆红找不到,或无法跳转过去,而自己的Linux机器往往缺乏各种C依赖库,配置安装比较麻烦,因此总体的思路是通过CLion远程连接SR社区已经安装完各种依赖库的Docker容器,进行编…...

数模测评:doubao1.5>deepseek-v3>gpt-o1
本次测试了当前评价最高的三款大模型doubao1.5、gpt-o1、deepseek-v3(r1崩溃),都是采用无提示词的硬核提问方式,测试视频如下。 gpto1、doubao1.5、deepseek测评 测试方式: 上传美赛六道题目文件 直接提问以下5句话: 这是一道数学…...

晴,初三,年已过
既然直播如此影响情绪,为什么还要直播?因为无聊?明明那么多事情可以打发时间。 真不想懂。 今日初三,昨天晚上小舅家聚,今天大舅家聚,计划明天小姨妈家聚。 今晚喝了点大舅哥哥泡的白葡萄酒,…...

Vue3 v-bind 和 v-model 对比
1. 基本概念 1.1 v-bind 单向数据绑定从父组件向子组件传递数据简写形式为 : 1.2 v-model 双向数据绑定父子组件数据同步本质是 v-bind 和 v-on 的语法糖 2. 基础用法对比 2.1 表单元素绑定 <!-- v-bind 示例 --> <template><input :value"text&quo…...

Smalltalk语言是何物?面向对象鼻祖Simula的诞生?Simula和Smalltalk有什么区别?面向对象设计?
Smalltalk语言是何物? Smalltalk语言的前身可以追溯到Flex系统,这是由Alan Kay最早提出的。在随后的发展中,Smalltalk逐渐演化,并出现了Smalltalk-72和Smalltalk-76等版本。最终,在经过近10年的研究与发展后,Xerox研究…...

KVM/ARM——基于ARM虚拟化扩展的VMM
1. 前言 ARM架构为了支持虚拟化做了些扩展,称为虚拟化扩展(Virtualization Extensions)。原先为VT-x创建的KVM(Linux-based Kernel Virtual Machine)适配了ARM体系结构,引入了KVM/ARM (the Linux ARM hypervisor)。KVM/ARM没有在hypervisor中引入复杂的…...