服务器重启或更改 xml 配置文件后如何保留 log4j2 的插件配置

How to retain log4j2's plugin configs after server restart or altering xml config file

我开发了一个自定义滚动文件附加程序,它工作正常。唯一的问题是每次我重新启动服务器或更改 log4j2.xml 文件(文件的任何部分)时它都会重新初始化,突然间所有以前的日志都会被擦除。我没有在随附的默认附加程序中观察到这种行为,所以我想知道如何才能保留我的配置。

<CustomAppender name="CustomAppender"
                                     fileName="${log.file.directory}/file.log"
                                     filePattern="${log.file.directory}/file.log.%d{yyyy-MM-dd}-%i.gz"
                                     immediateflush="true"
                                     append="true">
        <CustomLayout/>
        <Policies>
            <SizeBasedTriggeringPolicy size="3 KB"/>
            <TimeBasedTriggeringPolicy interval="1"/>
        </Policies>
    </CustomAppender>

P.S。我试图让它成为一个单例,但除此之外它没有用我真的不想让它远离被重新配置,我只想保留我以前生成的日志。

更新

显然,每次服务器关闭或 log4j2.xml 文件被更改时,管理器都会从头开始重建附加程序,尽管内置附加程序即使在重新启动或重新配置后也会保持其状态。他们通过覆盖 AbstractOutputStreamAppender 中的“stop”方法来做到这一点。我对我的 appender 做了同样的事情,但它仍然没有像我预期的那样表现。

@Override
public boolean stop(long timeout, TimeUnit timeUnit) {
    setStopping();
    final boolean stopped = super.stop(timeout, timeUnit, false);
    setStopped();
    return stopped;
}

这是我在 appender builder 中使用的管理器:

final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, append,
                isBufferedIo, policy, strategy, advertiseUri, layout, bufferSize, isImmediateFlush(),
                createOnDemand, filePermissions, fileOwner, fileGroup, getConfiguration());
        if (manager == null) {
            return null;
        }
        manager.initialize();

重新配置时会发生以下情况:

  1. 新的配置文件被读取并转换为节点树。
  2. 访问与节点关联的插件并创建其对应的类。
  3. 如果配置创建成功,它就会启动。
  4. 记录器已更新以引用新配置。
  5. 旧配置已停止。

如您所想,由于同时有两个配置 运行 这可能会导致问题。例如,如果两个组件都尝试使用同一个端口,那么第二个配置可能会失败。为了避免这些问题,Log4j 2 中的 Appenders 使用了 Managers。管理器通常会有一个“名称”,其中包括任何项目,如果它们在新配置中具有相同的值,则表明应该重用管理器。这允许像 OutputStreams 这样的东西在重新配置期间保持打开状态。但是,这样做的副作用是,如果参数在 appender 上更改并且不是“名称”的一部分,那么值的更改可能会被忽略,因为管理器未被修改。

因此,在创建新的Appender 时,必须注意传递给Manager 的名称,并且Appender 应尝试更新Manager 中不属于名称的相关值。此外,Manager 必须考虑到它被多次启动和停止。 AbstractManager 实际上会为您处理这个。