user1918737
user1918737

Reputation: 117

Logging to different files following parent context

I have a single back-office Java application built with Spring Boot, and I use SLF4J for logging (required). The application contains multiple jobs that run periodically.

I would like to log everything that happens during each of those jobs in a separate file. This would give me one log file per job, plus a general log file for the application startup and whatnot.

When it comes to the main class of the job, it is an easy task since all I need to do is to retrieve the logger I'm insterested in by name :

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

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

But the tricky part is to get the common resources called by the different jobs to log to the right file.

public class CommonDao {

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

What I want: when any method of CommonDao is called by SchedulerOne, the subsequent logs should appear in "logger_one". When the same method is called by SchedulerTwo, the logs should appear in "logger_two".

What currently happens: CommonDao ignores the context and just write to the default log file.

The only resource I could find on the subject is the logback documentation (https://logback.qos.ch/manual/loggingSeparation.html) which uses ContextJNDISelector to select the appropriate context when logging. This looks like what I aiming to do, but the instructions are aimed at applications containing multiple webapps. I only have one application that does not have a web.xml, so this does not seem applicable.

My current logback configuration is as follows:

<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>

Upvotes: 0

Views: 1116

Answers (2)

user65839
user65839

Reputation:

Rather than having CommonDao have a single static logger, you could pass in the logger for it to use as a parameter, either in each method you call on it or by having each job make its own instance of the class and pass the logger to use as the constructor.

It's a bit unconventional, but if you want your loggers to be named based on the job they're running rather than the class they're in, then it makes sense to me to have the logger be created and maintained by the job they're running, rather than just the class they're in.

Upvotes: 0

Konrad Botor
Konrad Botor

Reputation: 5043

You need to combine MDC with SiftingAppender like described here, so something like:

<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>

And then do MDC.put("context", "one") in SchedulerOne and MDC.put("context", "two") in SchedulerTwo.

Upvotes: 2

Related Questions