有没有办法在java中动态命名日志文件?

时间:2012-12-19 22:30:07

标签: java logging slf4j logback

我正在使用logback作为我的日志记录框架,并且有几个使用不同参数运行相同main函数的作业,并希望为每个作业创建一个日志文件,并使用该作业命名日志文件名。

例如,如果我的作业a,b,c全部运行MyClass.main(),但参数不同,那么我希望看到a-{date}.log, b-{date}.log, c-{date}.log

我可以通过在{date}中指定<fileNamePattern>myjob-%d{yyyy-MM-dd}.log</fileNamePattern>来实现logback.xml部分,但我不确定如何(或者如果可能的话)创建前缀动态文件名(作为作业的名称)。

有没有办法在logback中动态命名日志文件?是否有其他日志框架可以实现这一目标?

作为一个后续问题,我是否采取了一种糟糕的方法,让多个作业使用不同的参数调用相同的main函数,并希望在每个作业之后命名一个日志文件?如果有这种情况的标准/最佳实践解决方案?

编辑:为什么我想在作业名称之后命名每个日志文件的原因是每个作业自然地定义了“工作单元”,并且我更容易找到适当的日志文件,以防其中一个工作失败。我可以简单地将滚动日志文件用于作业a,b,c,但我发现查看日志并确定每个作业的开始和结束位置更加困难。

4 个答案:

答案 0 :(得分:2)

我会用你自己的记录。

public static PrintWriter getLogerFor(String prefix) {
     SimpleDatFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
     String filename= prefix + sdf.format(new Date());
     return new PrintWriter(filename, true); // auto flush.
}

您可以编写一个简单的LRU缓存,例如使用LinkedHashMap重用PrintWriters。

答案 1 :(得分:1)

  

有没有办法在logback中动态命名日志文件?是否有其他日志框架可以实现这一目标?

我不相信使用标准logback.xml文件配置的out of the box appenders(FileRollingFile等)是可行的。要做你想做的事,你需要动态地动态创建appender并将记录器分配给不同的appender。或者你需要发明一个新的appender,它足够智能,可以根据记录器名称同时写入多个文件。

  

我只是采取了一种糟糕的方法,让多个作业使用不同的参数调用相同的主函数,并希望在每个作业之后命名一个日志文件?

logback的作者在Mapped Diagnostic Context

部分解决了这个问题及slightly discourage
  

将一个客户端的日志记录输出与另一个客户端的日志记录输出区分开来的一种可能但稍微不鼓励的方法包括为每个客户端实例化一个新的独立记录器。这种技术促进了记录器的扩散,并可能增加其管理开销。 ...一种较轻的技术包括对给定客户端的每个日志请求进行唯一标记。

然后他们继续讨论映射的诊断上下文作为解决这个问题的方法。他们给出了一个NumberCruncherServer的例子,它可以同时处理不同线程中的各种客户端的数字。通过设置映射的诊断上下文和适当的日志记录模式,可以轻松确定哪个日志事件来自哪个客户端。然后,您只需使用grep工具将感兴趣的记录事件分离到单独的文件中即可进行详细分析。

答案 2 :(得分:0)

是的,你可以。

首先,您必须熟悉这两个概念:Logger和Appender。一般来说,您的代码获取Logger,并调用日志方法,如debug(),warn(),info()等.Logger附加了Appender,Appender根据设置的配置向用户显示日志信息。它

熟悉之后,您需要做的是为每个不同的作业类型动态创建一个具有不同文件名的FileAppender,并将其附加到Logger。

如果以上都没有意义,我建议您花一些时间使用logback手册。

答案 3 :(得分:0)

您可以使用logback鉴别符,因为鉴别器的键可以在<FileNamePattern>标记中使用。我可以想到两个选择:

选项一:

您可以使用Mapped Diagnostic Context鉴别器来实现日志记录分离,您需要使用MDC.put();

为每个作业设置不同的值

一旦你完成了这一点,你的注销配置的appender就会像:

<appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
    <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
        <key>jobName</key> <!-- the key you used with MDC.put() -->
        <defaultValue>none</defaultValue>
    </discriminator>
    <sift>
        <appender name="jobsLogs-${jobName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${jobName}.%d{dd-MM-yyyy}.log.zip</FileNamePattern>
                .
                .
                .
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>...</Pattern>
            </layout>
        </appender>
    </sift>
</appender>

选项二:

实现自己的鉴别器 - 实现ch.qos.logback.core.sift.Discriminator - ,以根据线程名称进行区分。看起来像这样:

public class ThreadNameDiscriminator implements Discriminator<ILoggingEvent> {

    private final String THREAD_NAME_KEY = "threadName";

    @Override
    public String getDiscriminatingValue(ILoggingEvent event) {
    return Thread.currentThread().getName();
    }

    @Override
    public String getKey() {
    return THREAD_NAME_KEY;
    }

    // implementation for more methods
    .
    .
    .
}

日志记录追加器看起来像选项一,鉴别器类为ThreadNameDiscriminator,密钥为threadName。在此选项中,无需从作业中为MDC设置值,因此不需要对它们进行任何修改。