根据父上下文记录到不同的文件

Logging to different files following parent context

我有一个使用 Spring Boot 构建的后台 Java 应用程序,我使用 SLF4J 进行日志记录(必需)。该应用程序包含多个定期 运行 的作业。

我想在单独的文件中记录每项工作期间发生的所有事情。这将为我提供每个作业一个日志文件,以及一个用于应用程序启动和诸如此类的一般日志文件。

当涉及到工作的主要 class 时,这是一项简单的任务,因为我需要做的就是按名称检索我感兴趣的记录器:

public class SchedulerOne extends Runnable {
    @Autowired
    private CommonDao commonDao;

    private static final Logger LOGGER = LoggerFactory.getLogger("logger_one");
    ...
}

但棘手的部分是让不同作业调用的公共资源记录​​到正确的文件中。

public class CommonDao {

    private static final Logger LOGGER = LoggerFactory.getLogger(CommonDao.class);
    ...
}

我想要的:当SchedulerOne调用CommonDao的任何一个方法时,后续的日志应该出现在"logger_one"中。当 SchedulerTwo 调用相同的方法时,日志应该出现在 "logger_two".

当前发生的情况:CommonDao 忽略上下文,只写入默认日志文件。

我能找到的关于该主题的唯一资源是 logback 文档 (https://logback.qos.ch/manual/loggingSeparation.html),它使用 ContextJNDISelector 在记录时 select 适当的上下文。这看起来像我的目标,但这些说明针对的是包含多个 Web 应用程序的应用程序。我只有一个应用程序没有 web.xml,所以这似乎不适用。

我目前的logback配置如下:

<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logger_default.log</file>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <Pattern>%d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
    </encoder>

    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
        <FileNamePattern>c:/jcg.%i.log.zip</FileNamePattern>
        <MinIndex>1</MinIndex>
        <MaxIndex>10</MaxIndex>
    </rollingPolicy>

    <triggeringPolicy
        class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
        <MaxFileSize>2MB</MaxFileSize>
    </triggeringPolicy>
</appender>

<appender name="SCHEDULER_ONE" class="ch.qos.logback.core.FileAppender">
        <file>scheduler_one.log</file>
        <append>true</append>
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
        </encoder>
</appender>

<logger name="logger_one" level="DEBUG" additivity="false">
    <appender-ref ref="SCHEDULER_ONE"/>
</logger>

<root level="DEBUG">
    <appender-ref ref="FILE" />
</root>

您需要像 here 中描述的那样将 MDC 与 SiftingAppender 结合起来,例如:

<configuration>
    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
        <discriminator>
            <defaultValue>default</defaultValue>
            <key>context</key>
        </discriminator>
        <sift>
            <appender name="FILE-${context}" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <file>logger_${context}.log</file>
                <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                    <Pattern>%d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
                </encoder>

                <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
                    <FileNamePattern>c:/jcg_${context}.%i.log.zip</FileNamePattern>
                    <MinIndex>1</MinIndex>
                    <MaxIndex>10</MaxIndex>
                </rollingPolicy>

                <triggeringPolicy
        class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                    <MaxFileSize>2MB</MaxFileSize>
                </triggeringPolicy>
            </appender>
        </sift>
    </appender>

    <logger name="logger_one" level="DEBUG" additivity="false">
        <appender-ref ref="SIFT"/>
    </logger>

    <root level="DEBUG">
        <appender-ref ref="SIFT" />
    </root>
</configuration>

然后在 SchedulerOne 中执行 MDC.put("context", "one"),在 SchedulerTwo 中执行 MDC.put("context", "two")

而不是让 CommonDao 有一个单一的静态记录器,您可以传入记录器以将其用作参数,在您调用它的每个方法中或让每个作业创建自己的实例class 并传递记录器以用作构造函数。

这有点不合常规,但如果您希望记录员根据他们 运行 的工作而不是 class 所从事的工作来命名,那么这对我来说很有意义让记录器由他们 运行 的工作创建和维护,而不仅仅是他们所在的 class。