Skip to content

Logback 手册 - 第十一章:从 log4j 版本 1.x 迁移

🏷️ Logback 手册


源自:https://logback.qos.ch/manual/migrationFromLog4j.html
作者:Ceki Gülcü, Sébastien Pennec, Carl Harris
版权所有 © 2000-2022 QOS.ch Sarl

本文档使用 署名 - 非商业性使用 - 相同方式共享 2.5 许可协议 许可发布


The more things change, the more they remain the same.

变化越大,越是一样。

——阿尔芬斯·卡尔,《黄蜂》


本章涉及将自定义的 log4j 1.x 组件(如附加器或布局)迁移到 logback-classic 的主题。

仅调用 log4j 1.x 客户端 API 的软件,即 org.apache.log4j 包中的 LoggerCategory 类,可以通过 SLF4J 迁移工具 自动迁移到使用 SLF4J。要将 log4j.property 文件迁移到其 logback 等效项,可以使用 log4j.properties 转换器

从更广泛的角度来看,log4j 和 logback-classic 密切相关。核心组件,如记录器、附加器和布局在两个框架中都存在并提供相同的用途。同样,最重要的内部数据结构,即 LoggingEvent,在两个框架中均存在,其实现相当类似但不完全相同。值得注意的是,在 logback-classic 中,LoggingEvent 实现了 ILoggingEvent 接口。将 log4j 组件迁移到 logback-classic 所需的大部分更改与 LoggingEvent 类的实现差异有关。请放心,这些差异相当有限。如果您尽最大努力仍无法将给定的 log4j 组件迁移到 logback-classic,请在 logback-dev 邮件列表 上发布问题。logback 的开发人员应能够提供指导。

迁移 log4j 布局

让我们从迁移一个名为 TrivialLog4jLayout 的假设和非常简单的 log4j 布局开始,该布局以日志事件中包含的消息作为格式化消息返回。以下是代码。

java
package chapters.migrationFromLog4j;

import org.apache.log4j.Layout;
import org.apache.log4j.​spi.LoggingEvent;

public class TrivialLog4jLayout extends Layout {

  public void activateOptions() {
    // 这里没有需要激活的选项
  }

  public String format(LoggingEvent loggingEvent) {
    return loggingEvent.getRenderedMessage(​);
  }

  public boolean ignoresThrowable() {
    return true;
  }
}

logback-classic 的等效项命名为 TrivialLogbackLayout,代码如下:

java
package chapters.migrationFromLog4j;

import ch.qos.logback.classic.​spi.ILoggingEvent;
import ch.qos.logback.core.​LayoutBase;

public class TrivialLogbackLayout extends LayoutBase<ILoggingEvent> {

  public String doLayout(ILoggingEvent loggingEvent) {
    return loggingEvent.getMessage();
  }
}

您可以看到,在 logback-classic 布局中,格式化方法的名称为 doLayout,而在 log4j 中为 format()ignoresThrowable() 方法在 logback-classic 中不需要,并且没有等价项。请注意,logback-classic 布局必须扩展 LayoutBase<ILoggingEvent> 类。

activateOptions() 方法值得进一步讨论。在 log4j 中,布局将由 log4j 配置器(即 PropertyConfiguratorDOMConfigurator)调用其 activateOptions() 方法,此方法在设置布局的所有选项后立即执行。因此,布局将有机会检查其选项是否一致,如果一致,则继续完全初始化自己。

在 logback-classic 中,布局必须实现 LifeCycle 接口,其中包括一个名为 start() 的方法。start() 方法相当于 log4j 的 activateOptions() 方法。

迁移 log4j 附加器

迁移附加器与迁移布局非常相似。以下是一个名为 TrivialLog4jAppender 的非常简单的附加器,它在控制台上写入其布局返回的字符串。

java
package chapters.migrationFromLog4j;

import org.apache.log4j.​AppenderSkeleton;
import org.apache.log4j.​spi.LoggingEvent;


public class TrivialLog4jAppender extends AppenderSkeleton {

  protected void append(LoggingEvent loggingevent) {
    String s = this.layout.format(​loggingevent);
    System.out.println(s);
  }

  public void close() {
    // 无需执行任何操作
  }

  public boolean requiresLayout() {
    return true;
  }
}

logback-classic 的等效项命名为 TrivialLogbackAppender,代码如下:

java
package chapters.migrationFromLog4j;

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

public class TrivialLogbackAppender extends AppenderBase<ILoggingEvent> {

  @Override
  public void start() {
    if (this.layout == null) {
      addError("未为名为 [" + name + "] 的附加器设置布局。");
      return;
    }
    super.start();
  }

  @Override
  protected void append(ILoggingEvent loggingevent) {
    // 请注意,仅当成功启动此附加器时,AppenderBase.doAppend 将调用此方法。
    
    String s = this.layout.doLayout(​loggingevent);
    System.out.println(s);
  }
}

比较这两个类,您应该注意到 append() 方法的内容保持不变。logback 中不使用 requiresLayout 方法,可以将其删除。在 logback 中,stop() 方法相当于 log4j 的 close() 方法。然而,在 logback-classic 中,AppenderBase 包含了 stop 的 nop 实现,对于这个简单的附加器来说已经足够了。