当前位置: 首页 > news >正文

log4j异常堆栈文件输出

目的:log4j异常堆栈关联到traceId一句话中,方便搜索

1、获取堆栈后一起打印

 private void logException(Throwable t, ProceedingJoinPoint joinPoint) {if (this.printErrorStackSys) {StringWriter sw = new StringWriter();PrintWriter pw = new PrintWriter(sw);t.printStackTrace(pw);String errorMsg = sw.toString();log.error("error->" + errorMsg);} else {// 子定义打印Signature signature = joinPoint.getSignature();String service = signature.toShortString();StringBuilder builder = new StringBuilder();builder.append("\r\n========================================== \r\n");builder.append("Invoke exception!!! \r\n");builder.append("Service = ").append(service).append("\r\n");Throwable cause = t.getCause();while (cause != null) {builder.append("\n\t\tCause: ").append(cause.getClass().getCanonicalName());builder.append(": ").append(cause.getMessage());cause = cause.getCause();}builder.append(" StackTrace=");StackTraceElement[] stackTraceElements = t.getStackTrace();for(int i = 0; i<stackTraceElements.length; i++){StackTraceElement stackTrace = stackTraceElements[i];builder.append(stackTrace.getClassName()).append(":").append(stackTrace.getMethodName()).append(":").append(stackTrace.getLineNumber()).append("\r\n;");}builder.append("\r\n==========================================");log.error(builder);}}

结果示例:
使用printStackTrace方法打印
在这里插入图片描述

自定义打印
在这里插入图片描述

2、使用%throwable打印堆栈跟踪信息

%throwable 用于在日志配置文件中输出异常的堆栈跟踪信息。
它不是 XML 的标准标签或属性,而是日志框架中的占位符

<!--控制台输出-->
<Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}|${ctx:uuid}|%t|%-5p|%c{1}:%L|%msg%n" /></Console>
<!--文件输出--><RollingFile name="RollingFile" filename="${logPath}/${rollingLogName}.log" filepattern="${logPath}/%d{yyyyMMdd}/${rollingLogName}-%i.log"><PatternLayout pattern='{"time":"%d{yyyy-MM-dd HH:mm:ss.SSS}","thread":"%t","tid":"${ctx:uuid}","level":"%-5p","class_line":"%c:%L","msg":"{%msg}%throwable"}%n'></PatternLayout><Policies><TimeBasedTriggeringPolicy interval="1" modulate="true" /><SizeBasedTriggeringPolicy size="1024 MB" /></Policies><DefaultRolloverStrategy max="100" /></RollingFile>

%d{HH:mm:ss,SSS} 表示日期和时间。
[%t] 表示线程名称。
%-5p 表示日志级别,左对齐,宽度为 5。
%c{1} 表示日志记录器的名称,只显示最后一级。
:%L 表示日志记录器的行号。
%m 表示日志消息。
%throwable 表示异常的堆栈跟踪信息。
%n 表示换行符。

结果示例:
在这里插入图片描述

3、自定义格式化插件

这种方式与2一样,2使用的是ThrowablePatternConverter

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.impl.LocationAware;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.ThrowablePatternConverter;@Plugin(name = "CustomerThrowablePatternConverter",category = "Converter"
)
@ConverterKeys({"ct", "customerThrowable"})public class CustomerThrowablePatternConverter extends ThrowablePatternConverter implements LocationAware {protected CustomerThrowablePatternConverter(String[] options, Configuration config) {super("CT", "CTStyle", options, config);}// 被触发的得到实例的方法public static CustomerThrowablePatternConverter newInstance(Configuration config, String[] options) {return new CustomerThrowablePatternConverter(options, config);}@Overridepublic void format(LogEvent event, StringBuilder buffer) {Throwable thrown = event.getThrown();if (thrown != null && thrown instanceof CustomerException) {buffer.append("自定义异常");}super.format(event, buffer);}// 位置信息@Overridepublic boolean requiresLocation() {return true;}
}

<PatternLayout pattern=‘{“tid”:“${ctx:uuid}”,“time”:“%d{yyyy-MM-dd HH:mm:ss.SSS}”,“thread”:“%t”,“level”:“%-5p”,“class_line”:“%c:%L”,“msg”:“%enc{%msg-%customerThrowable}{JSON}”}%n’>

在这里插入图片描述

4、源码分析

Disruptor 是一个高性能的无锁并发框架,常用于异步日志记录、消息传递等场景。

  • LogEvent:表示一个日志事件的类,将要输出的日志上下文信息封装成事件。
 public LogEvent createEvent(String loggerName, Marker marker, String fqcn, StackTraceElement location, Level level, Message data, List<Property> properties, Throwable t) {return new Log4jLogEvent(loggerName, marker, fqcn, location, level, data, properties, t);}
  • RingBuffer:一个循环缓冲区,用于存储事件数据。
 private static final EventTranslatorTwoArg<Log4jEventWrapper, LogEvent, AsyncLoggerConfig> TRANSLATOR = new EventTranslatorTwoArg<Log4jEventWrapper, LogEvent, AsyncLoggerConfig>() {public void translateTo(Log4jEventWrapper ringBufferElement, long sequence, LogEvent logEvent, AsyncLoggerConfig loggerConfig) {ringBufferElement.event = logEvent;ringBufferElement.loggerConfig = loggerConfig;}};
  • Sequencer:负责管理和分配序列号的组件。 方法用于发布一个序列号,表示某个事件已经准备好,可以被消费者线程处理。发布后的消息通常由一个或多个消费者类(也称为事件处理器或 EventHandler)进行消费。
private <A, B> void translateAndPublish(EventTranslatorTwoArg<E, A, B> translator, long sequence, A arg0, B arg1) {try {translator.translateTo(this.get(sequence), sequence, arg0, arg1);} finally {this.sequencer.publish(sequence);}}
  • EventHandler:负责处理事件的消费者类,定义了一个 onEvent 方法,该方法会在事件准备好后被调用。
   public void onEvent(Log4jEventWrapper event, long sequence, boolean endOfBatch) throws Exception {event.event.setEndOfBatch(endOfBatch);// 去消费event.loggerConfig.logToAsyncLoggerConfigsOnCurrentThread(event.event);event.clear();this.notifyIntermediateProgress(sequence);}

5、主要流程

org.apache.logging.log4j.core.async.AsyncLoggerConfig#log
->org.apache.logging.log4j.core.Logger#logMessage
->org.apache.logging.log4j.core.config.LoggerConfig#log(java.lang.String, java.lang.String, org.apache.logging.log4j.Marker, org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
->org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier<org.apache.logging.log4j.core.config.LoggerConfig>, java.lang.String, java.lang.String, org.apache.logging.log4j.Marker, org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
->org.apache.logging.log4j.core.appender.RollingFileAppender#append
->org.apache.logging.log4j.core.layout.PatternLayout#encode
->org.apache.logging.log4j.core.layout.PatternLayout.PatternSerializer#toSerializable(org.apache.logging.log4j.core.LogEvent, java.lang.StringBuilder)
->LogEventPatternConverter的子类进行格式化操作拼接打印日志输出

// 异步输出日志方法重写protected void log(LogEvent event, LoggerConfig.LoggerConfigPredicate predicate) {if (predicate == LoggerConfigPredicate.ALL && ASYNC_LOGGER_ENTERED.get() == Boolean.FALSE && this.hasAppenders()) {ASYNC_LOGGER_ENTERED.set(Boolean.TRUE);try {super.log(event, LoggerConfigPredicate.SYNCHRONOUS_ONLY);this.logToAsyncDelegate(event);} finally {ASYNC_LOGGER_ENTERED.set(Boolean.FALSE);}} else {super.log(event, predicate);}}
//父类的方法,1、同步日志调用, 2、EventHandler回调使用protected void log(LogEvent event, LoggerConfigPredicate predicate) {if (!this.isFiltered(event)) {this.processLogEvent(event, predicate);}}
// 日志处理--打印输出private void processLogEvent(LogEvent event, LoggerConfigPredicate predicate) {event.setIncludeLocation(this.isIncludeLocation());// 判断当前 !config instanceof AsyncLoggerConfig是否为非异步if (predicate.allow(this)) {// 打印处理this.callAppenders(event);}this.logParent(event, predicate);}
// 队列处理private void logToAsyncDelegate(LogEvent event) {if (!this.isFiltered(event)) {this.populateLazilyInitializedFields(event);// 发布序列号,添加到缓冲区if (!this.delegate.tryEnqueue(event, this)) {// 缓存区满了处理this.handleQueueFull(event);}}}public void format(LogEvent event, StringBuilder buf) {if (this.skipFormattingInfo) {this.converter.format(event, buf);} else {this.formatWithInfo(event, buf);}}
http://www.lryc.cn/news/482956.html

相关文章:

  • 在配置环境变量之后使用Maven报错 : mvn : 无法将“mvn”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
  • SpringSecurity源码中核心类
  • 【JAVA】使用IDEA创建maven聚合项目
  • 猿创征文|Inscode桌面IDE:打造高效开发新体验
  • 概率论中的PMF、PDF和CDF
  • Vue 简单入手
  • Github配置ssh key原理及操作步骤
  • 大循环引起CPU负载过高
  • [Java]微服务治理
  • 深入解析C语言中的extern关键字:语法、工作原理与高级应用技巧
  • 元器件封装
  • 状态空间方程离散化(Matlab符号函数)卡尔曼
  • 软件设计师-计算机网络
  • SpringBoot操作Elasticsearch
  • 阿里云aliyun gradle安装包下载地址
  • 【设计模式】创建型设计模式-工厂模式的实现
  • 【分布式】CAP理论
  • 市域社会治理现代化解决方案-2
  • 谷歌浏览器的自动翻译功能如何开启
  • Linux设置socks代理
  • 【ACM出版】第四届信号处理与通信技术国际学术会议(SPCT 2024)
  • 蓝队技术学习
  • openpyxl处理Excel模板,带格式拷贝行和数据填入
  • 无法在带有 WHM/cPanel 的 Ubuntu 22.04 服务器上安装 PHP 7.x – 缺少软件包
  • 数据结构-递归函数的调用栈过程
  • 在 WPF 中,如何实现数据的双向绑定?
  • pyinstaller 打包 playwright -- 如何将浏览器打包到程序中
  • vue系列=状态管理=Pinia使用
  • [HarmonyOS]简单说一下鸿蒙架构
  • 【Python TensorFlow】进阶指南(续篇一)