log4j异常堆栈文件输出

news2024/11/24 13:23:13

目的: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);
    }
    @Override
    public void format(LogEvent event, StringBuilder buffer) {
        Throwable thrown = event.getThrown();
        if (thrown != null && thrown instanceof CustomerException) {
            buffer.append("自定义异常");
        }

        super.format(event, buffer);
    }

    // 位置信息
    @Override
    public 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.coloradmin.cn/o/2239278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ReactPress:构建高效、灵活、可扩展的开源发布平台

ReactPress Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎Star。 在当今数字化时代&#xff0c;内容管理系统&#xff08;CMS&#xff09;已成为各类网站和应用的核心组成部分。ReactPress&#xff0c;作为一款融合了现代Web开发多项先进技术的开…

【笔记】Springboo项目启动失败

application run failed org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name adviceMapper defined in file 原因是mybatisplus和springboot的版本不匹配 修改后&#xff1a; springboot mybatisplus 成功

PET-文件包含

include发生错误报warning&#xff0c;继续执行。require发生错误直接error&#xff0c;不继续执行 无视扩展名&#xff0c;只要能解析&#xff0c;就能当可执行文件执行&#xff0c;哪怕文件后缀或没后缀 1 条件竞争 pass17 只需要知道tmp的路径。把xieshell.jpg上传&…

强化学习入门笔记(Reinforcement Learning,RL) 强推!

由于本人的近期研究方向涉及到强化学习&#xff0c;本科时已经学习过了&#xff0c;但是感觉还是有些概念和算法没有学懂学透&#xff0c;所以想重新系统性的学习一下&#xff0c;记录了整个学习过程&#xff0c;而且对当时没有理解不是特别深刻的内容有了一些更加深刻的理解&a…

HTB:Photobomb[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机进行端口开放扫描 再次使用nmap对靶机开放端口进行脚本、服务扫描 使用ffuf进行简单的子域名扫描 使用浏览器直接访问该域名 选取一个照片进行下载&#xff0c;使用Yakit进行抓包 USER_FLAG&#xff1a;a9afd9220ae2b5731…

Golang | Leetcode Golang题解之第560题和为K的子数组

题目&#xff1a; 题解&#xff1a; func subarraySum(nums []int, k int) int {count, pre : 0, 0m : map[int]int{}m[0] 1for i : 0; i < len(nums); i {pre nums[i]if _, ok : m[pre - k]; ok {count m[pre - k]}m[pre] 1}return count }

【Vue】Vue3.0(二十)Vue 3.0 中mitt的使用示例

上篇文章 【Vue】Vue3.0&#xff08;十九&#xff09;Vue 3.0 中一种组件间通信方式-自定义事件 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月11日12点23分 文章目录 一、mitt 在…

降SAR需求分析

1、需求分析 在信息技术领域&#xff0c;SAR 可能代表 "Specific Absorption Rate"&#xff0c;即特定吸收率。这是用于衡量无线设备&#xff08;如手机&#xff09;辐射对人体的吸收程度的标准。国外认证机构针对手机有相关辐射值要求&#xff0c;比如通话场景等&am…

如何学习VBA_3.2.14:字符串的处理

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效率&#xff0c;而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册&#xff0c;现在已经全部完成&#xff0c;希望大家利用、学习。 如果…

Processing Modflow软件安装,建立地下水-地面沉降数值模型的流程与步骤(构造沉降、抽水沉降、采空沉降等);三维地质建模数据处理

目前&#xff0c;地面沉降问题是我国较为常见的环境地质问题&#xff0c;其巨大的破坏力严重影响城市建筑安全和交通轨道运行。围绕地面沉降的防控与治理&#xff0c;是工程地质、环境地质、轨道交通设计等相关技术人员十分关注的领域&#xff0c;而数值模拟技术是评估防控效果…

Leetcode刷题Python之3258.统计满足k约束的子字符串I

提示&#xff1a;暴力解法简单易懂能通过。 文章目录 一、题目描述示例分析 二、解题思路三、代码实现代码解析 总结 一、题目描述 给定一个二进制字符串 s&#xff08;即字符串中只包含字符 0 和 1&#xff09;以及一个整数 k。要求计算出 s 中满足 “k 约束” 的子字符串数量…

链游系统定制化开发:引领游戏产业的新时代

在数字革命的浪潮中&#xff0c;链游&#xff08;区块链游戏&#xff09;作为一种新兴游戏形式&#xff0c;正重新定义游戏产业的发展方向。链游将区块链技术与传统游戏结合&#xff0c;使游戏体验更加公平透明&#xff0c;并赋予玩家真正的资产所有权。这一领域不仅为玩家带来…

【AI换装整合包及教程】CatVTON与其他虚拟试衣技术的详细对比

一、概述 虚拟试衣技术近年来发展迅猛&#xff0c;尤其在电商领域的应用备受瞩目。CatVTON作为一种新兴的虚拟试衣技术&#xff0c;凭借其轻量化设计和高效训练策略脱颖而出。本文将从网络结构、训练策略、推理过程及应用场景四个方面详细对比CatVTON与其他主流虚拟试衣技术。…

元宇宙及其技术

“元宇宙”&#xff08;Metaverse&#xff09;是一个结合了现实与虚拟的数字世界的概念。这个词最早由作家尼尔斯蒂芬森&#xff08;Neal Stephenson&#xff09;在其1992年的科幻小说《雪崩》&#xff08;Snow Crash&#xff09;中提出。元宇宙通常被描述为一个共享的虚拟空间…

三种单例实现

1、不继承Mono的单例 实现 使用 注&#xff1a; 使用需要继承BaseManager 泛型填写自己本身 需要实现无参构造函数 2、挂载式的Mono单例 实现 使用 注&#xff1a; 使用需要继承SingletonMono 泛型填写自己本身 需要挂载在unity引擎面板 3、不用挂载式的单例 实现 使…

移动取证和 Android 安全

当今的数字时代已经产生了许多技术进步&#xff0c;无论是智能手机还是虚拟现实、人工智能和物联网 (IoT) 等下一代基础技术。 智能手机已不再只是奢侈品&#xff0c;而是我们生存所必需的东西。根据各种统计数据&#xff0c;如今全球有超过 50% 的人使用手机。 由于数据存储…

视频孪生技术在金融银行网点场景中的应用价值

作为国民经济重要的基础行业&#xff0c;金融行业在高速发展的同时衍生出业务纠纷、安全防范、职能管理等诸多问题&#xff0c;对安全防范和监督管理提出了更高的要求。因此&#xff0c;如何能更好的利用视频监控系统价值&#xff0c;让管理人员更简便的浏览监控视频、更快速的…

Prompt Engineering 提示工程

一、什么是提示工程&#xff08;Prompt Engineering&#xff09; Prompt 就是发给大模型的指令&#xff0c;比如讲个笑话、用 Python 编个贪吃蛇游戏等&#xff1b;大模型只接受一种输入&#xff0c;那就是 prompt。本质上&#xff0c;所有大模型相关的工程工作&#xff0c;都是…

【大语言模型】ACL2024论文-09 无监督信息精细化训练用于增强大型语言模型的检索增强生成

【大语言模型】ACL2024论文-09 无监督信息精细化训练用于增强大型语言模型的检索增强生成 目录 文章目录 【大语言模型】ACL2024论文-09 无监督信息精细化训练用于增强大型语言模型的检索增强生成目录1. 论文信息2. 摘要3. 研究背景4. 问题与挑战5. 如何解决6. 创新点7. 算法模…

【服务器】使用命令行文本编辑器(如 vim、nano 或 vi)创建文件并编辑

【服务器】使用命令行文本编辑器&#xff08;如 vim、nano 或 vi&#xff09;创建文件并编辑 准备&#xff1a;连接至服务器&#xff08;如ssh&#xff09;创建 .ncl 文件方法 1: 使用 vim 创建 .ncl 文件方法 2: 使用 nano 创建 .ncl 文件确认文件已创建运行 .ncl 文件 总结参…