目的: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;
- }
- }
复制代码 < atternLayout 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);
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |