动态选择日志文件

时间:2017-03-01 20:12:18

标签: java logging log4j2

我有一个应用程序,其中包含许多在数据库中创建数据的组件。每个组件记录创建数据时的操作。有许多这样的组件,应用程序是灵活的,因此每次运行时并不总是需要执行相同的这些数据创建组件集。

目前,所有内容都记录到单个文件,这会生成开始变得无法管理的文件。我喜欢它,如果每个组件都可以登录到 name 描述哪个组件写入它的文件 - ComponentA应该登录到ComponentA-dataCreationPhase.log

我见过的大多数解决方案似乎都假设不同的记录器是静态的,因此可以按名称查找它们,例如LogManager.getLogger("ComponentA"); - 假设记录器具有该名称已在我的log4j2.xml中配置。我见过的其他解决方案使用了Routing和ThreadContexts - 但我不确定这是否可行,因为这些组件可能都在同一个线程中执行。

如何获取每个组件(许多是不同的类,但有些只是相同类的不同实例,只是配置不同)才能登录到自己的日志文件?理想情况下,这将基于现有的log4j2.xml文件完成,因为log4j2.xml可能具有一些用户指定的配置,我希望将这些配置传播到特定于组件的记录器,例如日志记录路径和日志记录级别

1 个答案:

答案 0 :(得分:0)

我找到了这个答案:

https://stackoverflow.com/a/38096181/192801

我使用它作为我通过顶层界面中的默认方法添加到所有Components的新函数的基础。

添加到所有组件的界面:

public interface Component {

default Logger createLogger(String logFileName, String oldAppenderName, String newAppenderName, boolean append, Level level)
{
    LoggerContext context = (LoggerContext) LogManager.getContext(false);
    Configuration configuration = context.getConfiguration();

    Appender oldAppender = configuration.getAppender(oldAppenderName);

    Layout<? extends Serializable> oldLayout = oldAppender.getLayout();

    // create new appender/logger
    LoggerConfig loggerConfig = new LoggerConfig(logFileName, level, false);

    Appender appender ;
    // In my case, it is possible that the old appender could
    // either be a simple FileAppender, or a  RollingRandomAccessFileAppender,
    // so I'd like the new one to be of the same type as the old one.
    // I have yet to find a more elegant way to do create a new Appender
    // of *any* type and then copy all relevant config.
    if (oldAppender instanceof RollingRandomAccessFileAppender)
    {
        int bufferSize = ((RollingRandomAccessFileAppender)oldAppender).getBufferSize();

        RollingRandomAccessFileManager oldMananger = (RollingRandomAccessFileManager)((RollingRandomAccessFileAppender) oldAppender).getManager();

        TriggeringPolicy triggerPolicy = oldMananger.getTriggeringPolicy();
        RolloverStrategy rollStrategy = oldMananger.getRolloverStrategy();
        Filter filter = ((RollingRandomAccessFileAppender)oldAppender).getFilter();
        // Inject new log file name into filePattern so that file rolling will work properly 
        String pattern = ((RollingRandomAccessFileAppender)oldAppender).getFilePattern().replaceAll("/[^/]*-\\%d\\{yyyy-MM-dd\\}\\.\\%i\\.log\\.gz", "/"+logFileName+"-%d{yyyy-MM-dd}.%i.log.gz");
        appender = RollingRandomAccessFileAppender.newBuilder()
                                           .withFileName("logs/" + logFileName + ".log")
                                           .withFilePattern(pattern)
                                           .withAppend(append)
                                           .withName(newAppenderName)
                                           .withBufferSize(bufferSize)
                                           .withPolicy(triggerPolicy)
                                           .withStrategy(rollStrategy)
                                           .withLayout(oldLayout)
                                           .withImmediateFlush(true)
                                           .withFilter(filter)
                                           .build();
    }
    else
    {
        appender = FileAppender.newBuilder()
                               .withFileName("logs/" + logFileName + ".log")
                                .withAppend(append)
                                .withName(newAppenderName)
                                .withLayout(oldLayout)
                                .setConfiguration(configuration)
                                .withLocking(false)
                                .withImmediateFlush(true)
                                .withIgnoreExceptions(true)
                                .withBufferSize(8192)
                                .withFilter(null)
                                .withAdvertise(false)
                                .withAdvertiseUri("")
                            .build();
    }
    appender.start();
    loggerConfig.addAppender(appender, level, null);
    configuration.addLogger(logFileName, loggerConfig);
    context.updateLoggers();

    return context.getLogger(logFileName);
}

此功能的使用发生在组件的构造函数中:

public class ComponentA implements Component
{
    private Logger logger = LogManager.getLogger();
    public ComponentA(String componentName)
    {
        this.logger = this.createLogger(componentName, "MyOriginalFileAppender", componentName+"Appender", true, Level.DEBUG, this.logger);
    }
}

和其他地方:

ComponentA fooSubtypeAComponent = new ComponentA("FooA");
ComponentA barSubtypeAComponent = new ComponentA("BarA");
ComponentB fooVariantTypeBComponent = new ComponentB("FooB");

Log4j配置中的原始Appenders + Loggers片段:

<Appenders>
    <!-- STDOUT appender. -->
    <Console name="Console" target="SYSTEM_OUT">
        <PatternLayout
            pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36}#%M - %msg%n" />
    </Console>

    <RollingRandomAccessFile name="MyOriginalFileAppender" fileName="${baseDir}/${defaultLogName}.log" filePattern="${baseDir}/$${date:yyyy-MM}/${defaultLogName}-%d{MM-dd-yyyy}.%i.log.gz">
        <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}#%M - %msg%n" />
        <Policies>
            <!-- <TimeBasedTriggeringPolicy /> -->
            <!-- Let's try cron triggering policy configured to trigger every day at midnight -->
            <CronTriggeringPolicy schedule="0 0 0 * * ?"/>
            <SizeBasedTriggeringPolicy size="25 MB" />
        </Policies>
    </RollingRandomAccessFile>
</Appenders>
<Loggers>
    <Root level="debug">
        <!-- only write INFO level to the file. -->
        <AppenderRef ref="MyOriginalFileAppender" level="debug"/>
        <!-- Console shows everything at DEBUG level-->
        <AppenderRef ref="Console" level="info" />
    </Root>
</Loggers>

结果应该是三个日志文件:logs/FooA.loglogs/BarA.loglogs/FooB.log - 上面显示的每个实例的一个日志文件。仍有一些问题需要解决,但我认为这样可以解决问题。