如何在 Spring 下配置 Logback

How to configure Logback under Spring

配置 Logback 的大多数示例使用 logback.xml。但是,我的应用程序使用 profiles and PropertySourcesPlaceholderConfigurer 的 Spring 功能将特定于环境的配置注入到需要它的组件中。像我的其他 Spring 组件一样以编程方式配置 Logback 的正确方法是什么?

在我们的一个项目中,我们是这样编码的:

import java.io.IOException;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;

@Component
public class InitializationService implements ApplicationListener<ContextRefreshedEvent> {

    @Value("${logbackErrorMailPassword}")
    private String logbackErrorMailPassword;

    @Value("${supportEmail}")
    private String supportEmail;

    @Value("${spring.profiles.active}")
    private String env;

    @Value("${log.dir}")
    private String logDir;

    @Value("${log.name}")
    private String logName;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {

        try {
            configureLogback();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void configureLogback() throws IOException {

        // assume SLF4J is bound to logback in the current environment
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        try {
            JoranConfigurator jc = new JoranConfigurator();
            jc.setContext(context);
            context.reset(); // override default configuration
            // inject the name of the current application as "application-name"
            // property of the LoggerContext
            context.putProperty("LOG_DIR", logDir);
            context.putProperty("LOG_NAME", logName);

            context.putProperty("ERROR_MAIL_PASSWORD", logbackErrorMailPassword);
            context.putProperty("SUPPORT_EMAIL_ID", supportEmail);
            context.putProperty("ENV", env);
            //jc .doConfigure(servletContext.getRealPath("/WEB-INF/my-logback.xml"));
            jc.doConfigure(new ClassPathResource("my-logback.xml").getInputStream());
        } catch (JoranException je) {
              // StatusPrinter will handle this
        }
        StatusPrinter.printInCaseOfErrorsOrWarnings(context);

    }
}

my-logback.xml 住在 src/main/resources,看起来像这样:

<configuration debug="true" scan="true" scanPeriod="10 minutes"> 
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%date %level [%thread] %logger %msg%n</Pattern>
        </encoder>
    </appender>
    <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${LOG_DIR}${LOG_NAME}.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <FileNamePattern>
           ${LOG_DIR}${LOG_NAME}-%d.%i.log.gz
          </FileNamePattern>
          <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <MaxFileSize>10MB</MaxFileSize>
          </TimeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
          <Pattern>%date %level [%thread] %logger %msg%n</Pattern>
        </encoder>
    </appender>
    <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!-- deny all events with a level below ERROR -->
            <level>ERROR</level>
        </filter>

        <smtpHost>xxxxxx.bluehost.com</smtpHost>
        <smtpPort>465</smtpPort>
        <username>xxxxxxx+xxxxx.com</username>
        <password>${ERROR_MAIL_PASSWORD}</password>
        <SSL>true</SSL>

        <to>${SUPPORT_EMAIL_ID}</to>
        <!-- Multiple to elements are permitted -->

        <from>xxxxx@xxxxx.com</from>
        <subject>[${ENV}] ERROR in ${LOG_NAME}</subject>
        <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
              <bufferSize>1</bufferSize>
        </cyclicBufferTracker>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date %-5level %logger{35} - %message%n</pattern>
        </layout>
    </appender>
    <logger name="javax.net" level="info"/>
    <logger name="javax.management" level="info"/>
    <logger name="org.springframework" level="info"/>
    <logger name="org.compass" level="info"/>
    <logger name="org.tuckey" level="info"/>
    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="ROLLING" />
        <appender-ref ref="EMAIL" />
    </root>

</configuration>

正如 orid 指出的那样,在 Spring 中使用 Logback 的官方方法是 the Logback Spring extension.

真正酷的是 Logback Spring 扩展在 Spring 或 servlet 之前启动并存储日志消息,直到配置 Appender。 (简单的附加程序将立即可用,而需要 Spring 的附加程序将通过 DelegatingLogbackAppender 代理)。

此外,您还可以:

  • 使用 SLF4J 的 java.util.logging 桥。
  • 使用 Spring resource path and system property 占位符指定 logback.xml 位置。
  • 使用logback.xml内的预设系统属性webapp.root(解压WAR目录的路径)设置日志文件路径等