java · 2025-09-30 0

logback 自定义 Appender 和 AsyncAppender

1.pom

<!-- slf4j依赖包 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>

<!-- logback-classic桥接器 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

<!-- logback实现 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.11</version>
</dependency>

2.appender

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;

import java.text.SimpleDateFormat;

public class CustomAppender extends AppenderBase<ILoggingEvent> {

    // 自定义属性
    private String systemName = "DEFAULT";

    @Override
    protected void append(ILoggingEvent event) {
        System.out.println(String.format("systemName: %s, msg: %s, threadName: %s, currentThreadName: %s",
                systemName,
                event.toString(),
                event.getThreadName(),
                Thread.currentThread().getName()));
    }

    // 提供 setter 方法,支持 logback.xml 配置
    public void setSystemName(String systemName) {
        this.systemName = systemName;
    }
}

3.注册 appender

AsyncAppender 的核心机制:它只是一个“包装器”,自己不写日志,必须通过 <appender-ref> 引用其他真正的 Appender

方式一:通过 xml 方式

<configuration>
    <!-- 控制台 Appender -->
    <appender name="CONSOLE_1" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 自定义 Appender -->
    <appender name="CUSTOM_APPENDER_1" class="org.example.CustomAppender">
        <systemName>test1</systemName>
    </appender>

    <!-- 异步 Appender -->
    <appender name="ASYNC_APPENDER_1" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="CUSTOM_APPENDER_1"/>
    </appender>

    <!-- 根日志器使用 CONSOLE Appender -->
    <root level="INFO">
        <appender-ref ref="CONSOLE_1" />
        <appender-ref ref="CUSTOM_APPENDER_1" />
        <appender-ref ref="ASYNC_APPENDER_1" />
    </root>
</configuration>

方式二:通过 java 方式

import ch.qos.logback.classic.AsyncAppender;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.layout.TTLLLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        // addConsoleAppender();
        // addCustomAppender();
        // addAsyncAppender();

        org.slf4j.Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("Hello 1");

        TimeUnit.SECONDS.sleep(5);
    }

    private static void addConsoleAppender() {
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

        // PatternLayout layout = new PatternLayout();
        // layout.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
        TTLLLayout layout = new TTLLLayout();
        layout.setContext(lc);
        layout.start();

        LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder<>();
        encoder.setContext(lc);
        encoder.setLayout(layout);

        ConsoleAppender<ILoggingEvent> ca = new ConsoleAppender<>();
        ca.setContext(lc);
        ca.setName("CONSOLE_1");
        ca.setEncoder(encoder);
        ca.start();

        Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
        rootLogger.addAppender(ca);
    }

    private static void addCustomAppender() {
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

        CustomAppender ca = new CustomAppender();
        ca.setName("CUSTOM_APPENDER_2");
        ca.setSystemName("MY_SYSTEM_NAME_2");
        ca.setContext(lc);
        ca.start();

        Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
        rootLogger.addAppender(ca);
    }

    private static void addAsyncAppender() {
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

        CustomAppender c = new CustomAppender();
        c.setName("CUSTOM_APPENDER_2");
        c.setSystemName("MY_SYSTEM_NAME_2");
        c.setContext(lc);
        c.start();

        AsyncAppender ca =  new AsyncAppender();
        ca.setName("ASYNC_APPENDER_1");
        ca.setContext(lc);
        ca.addAppender(c);
        ca.start();

        Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
        rootLogger.addAppender(ca);
    }
}

4.结果

23:21:32 [main] INFO  org.example.Main - Hello 1
systemName: test1, msg: [INFO] Hello 1, threadName: main, currentThreadName: main
systemName: test1, msg: [INFO] Hello 1, threadName: main, currentThreadName: AsyncAppender-Worker-ASYNC_APPENDER_1