Contents

Logback 实现自定义 appender

1. 简介

在本文中,我们将探索创建自定义 Logback appender。如果您正在寻找有关登录 Java 的介绍,请查看这篇文章

Logback 附带了许多写入标准输出、文件系统或数据库的内置附加程序。这个框架架构的美妙之处在于它的模块化,这意味着我们可以很容易地定制它。

在本教程中,我们将重点关注logback-classic,它需要以下 Maven 依赖项:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.6</version>
</dependency>

Maven Central 上提供了此依赖项的最新版本。

2. 基本的 Logback Appender

Logback 提供了我们可以扩展以创建自定义附加程序的基类。

Appender是所有 appender 必须实现的通用接口。泛型类型是ILoggingEventAccessEvent,这取决于我们分别使用的是logback-classic还是logback-access

**我们的自定义 appender 应该扩展AppenderBaseUnsynchronizedAppenderBase,**它们都实现Appender并处理过滤器和状态消息等功能。

AppenderBase是线程安全的;UnsynchronizedAppenderBase子类负责管理它们的线程安全。

正如ConsoleAppenderFileAppender都扩展了OutputStreamAppender并调用了超级方法*setOutputStream()*一样,如果自定义 appender正在写入 OutputStreamAppender,它应该是 OutputStreamAppender 的子类。

3. 自定义Appender

对于我们的自定义示例,我们将创建一个名为MapAppender的玩具附加程序。此附加程序会将所有日志记录事件插入到ConcurrentHashMap中,并带有键的时间戳。首先,我们将继承AppenderBase并使用ILoggingEvent作为通用类型:

public class MapAppender extends AppenderBase<ILoggingEvent> {
    private ConcurrentMap<String, ILoggingEvent> eventMap 
      = new ConcurrentHashMap<>();
    @Override
    protected void append(ILoggingEvent event) {
        eventMap.put(System.currentTimeMillis(), event);
    }

    public Map<String, ILoggingEvent> getEventMap() {
        return eventMap;
    }
}

接下来,为了让MapAppender开始接收日志事件,让我们将它作为附加程序添加到我们的配置文件logback.xml 中

<configuration>
    <appender name="map" class="com.blogdemo.logback.MapAppender"/>
    <root level="info">
        <appender-ref ref="map"/>
    </root>
</configuration>

4.设置属性

Logback 使用 JavaBeans 自省来分析在 appender 上设置的属性。我们的自定义 appender 将需要 getter 和 setter 方法来允许内省器查找和设置这些属性。

让我们向MapAppender添加一个属性,为eventMap的键提供前缀:

public class MapAppender extends AppenderBase<ILoggingEvent> {
    //...
    private String prefix;
    @Override
    protected void append(ILoggingEvent event) {
        eventMap.put(prefix + System.currentTimeMillis(), event);
    }
    public String getPrefix() {
        return prefix;
    }
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
    //...
}

接下来,在我们的配置中添加一个属性来设置这个前缀:

<configuration debug="true">
    <appender name="map" class="com.blogdemo.logback.MapAppender">
        <prefix>test</prefix>
    </appender>
    //...
</configuration>

5. 错误处理

为了在自定义 appender 的创建和配置过程中处理错误,我们可以使用从AppenderBase继承的方法。

例如,当前缀属性为 null 或空字符串时,MapAppender可以调用*addError()*并提前返回:

public class MapAppender extends AppenderBase<ILoggingEvent> {
    //...
    @Override
    protected void append(final ILoggingEvent event) {
        if (prefix == null || "".equals(prefix)) {
            addError("Prefix is not set for MapAppender.");
            return;
        }
        eventMap.put(prefix + System.currentTimeMillis(), event);
    }
    //...
}

当在我们的配置中打开调试标志时,我们将在控制台中看到一个错误,提醒我们前缀属性尚未设置:

<configuration debug="true">
    //...
</configuration>