【问题标题】:Problems of print java exceptions in one line by logback for dockerdocker logback 一行打印java异常的问题
【发布时间】:2017-08-29 03:04:19
【问题描述】:

我要将我的 java 应用程序放入 docker。但是根据我们公司的日志记录,我必须使用fluentd 来收集容器的日志。这需要我将 java stacktraces 放到一行日志中。

我做了以下,它在某些情况下有效,但在其他情况下失败。

package com.alex;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.zip.DataFormatException;

public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    public static void alexExc() throws Exception {
        throw new Exception("hello");
    }

    public static void main(String[] args) throws Exception {
        try {
            alexExc();
        } catch (Throwable t) {
            logger.error("oops", t);
        }

        throw new DataFormatException("invalid data format");
    }
}

以下是我的转换器,用我指定的“#012”替换分隔符

package com.alex;

import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.core.CoreConstants;

public class OneLineStackTraceConverter extends ThrowableProxyConverter {
    protected String throwableProxyToString(IThrowableProxy tp) {
        String originalStackTrace = super.throwableProxyToString(tp);

        return originalStackTrace.replace(CoreConstants.LINE_SEPARATOR, " #012");
    }
}

然后是我的 logback 配置:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="30 seconds">
    <conversionRule  conversionWord="ex"
            converterClass="com.alex.OneLineStackTraceConverter" />

    <appender name="INFO_FILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/logs/loggingmdc/info.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>/logs/loggingmdc/info.log.%i</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>5</maxIndex>
        </rollingPolicy>
        <triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>1GB</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %le %logger{0}: ## %msg\n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <appender name="DEBUG_FILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/logs/loggingmdc/debug.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>/logs/loggingmdc/debug.log.%i</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>5</maxIndex>
        </rollingPolicy>
        <triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>1GB</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %le %logger{0}: ## %msg %ex\n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <appender name="ERROR_FILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/logs/loggingmdc/error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>/logs/loggingmdc/error.log.%i</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>5</maxIndex>
        </rollingPolicy>
        <triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>1GB</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %le %logger{0}: ## %msg %ex\n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <appender name="THIRD_PARTY_FILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/logs/loggingmdc/thirdparty.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>/logs/loggingmdc/thirdparty.log.%i</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>5</maxIndex>
        </rollingPolicy>
        <triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>1GB</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %le %logger{0}: ## %msg %ex\n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="THIRD_PARTY_FILE"/>
    </root>
    <logger name="com.alex" level="DEBUG" additivity="false">
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="DEBUG_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </logger>
</configuration>

正如您在我的 logback 配置中看到的那样,我添加了一个 conversionRule 以指定日志记录事件中的异常是使用我的 OneLineStackTraceConverter

  1. 如果我在编码器的每个模式中包含 %ex,它就可以工作
  2. 如果我不在模式中包含%ex,它将不起作用。为什么?如果用户忘记在其模式中包含 %ex,我是否有其他的转换字可用于该异常?
  3. 最后一个DataFormatException 没有进入日志文件,它出现在控制台中,我也希望它进入日志文件。我怎样才能做到这一点?

谢谢。

【问题讨论】:

    标签: java logback


    【解决方案1】:

    如果我不在模式中包含 %ex,它就不起作用。为什么?

    因为您声明了转换字 = ex。如果你不使用它,Logback 不知道你在想什么,所以它什么也做不了。对比一下在代码中声明一个变量而不使用它,你应该就能明白了。

    最后一个DataFormatException没有进入日志文件

    因为就您的代码而言,它没有被记录。如果您在代码中抛出异常,Logback(或 SLF4J 在您的情况下)不会自动捕获并记录它。

    【讨论】:

    • 感谢您的回复。对于第一个,我完全理解你的解释。但是当我在模式中使用%ex 时,堆栈跟踪应该被格式化为一行。如果我在模式中删除%ex,堆栈跟踪也在日志文件中,但它们仍然是原始的多行堆栈跟踪,而不是使用我指定的转换器。对于第二个,我有什么方法可以将异常也指向日志文件吗?
    • @Alex 1) Logback 将日志语句与模式匹配。如果您没有为您的日志语句提供自定义解析器,它只会将它们作为消息的一部分转储到附加程序。这类似于正则表达式匹配 - 仅匹配您指定的部分。 2) 你可以声明一个控制台appender,也可以使用fluentd来抽取Docker日志。
    猜你喜欢
    • 2019-01-25
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    相关资源
    最近更新 更多