我们有多个并发运行的作业,它们必须使用相同的 log4j 配置信息。他们都使用相同的附加程序将日志转储到一个文件中。有没有办法让每个作业动态命名其日志文件,以便它们保持独立?

谢谢
汤姆

有帮助吗?

解决方案

您能为每个作业传递一个 Java 系统属性吗?如果是这样,您可以像这样参数化:

java -Dmy_var=somevalue my.job.Classname

然后在你的 log4j.properties 中:

log4j.appender.A.File=${my_var}/A.log

您可以使用主机环境(例如)中的值填充 Java 系统属性,该值将唯一标识作业实例。

其他提示

如果提前知道作业名称,则可以在执行 getLogger() 调用时包含作业名称。然后,您可以使用单独的文件名(或其他目标)将不同的附加程序绑定到不同的记录器。

如果您无法提前知道作业名称,您可以在运行时配置记录器,而不是使用配置文件:

FileAppender appender = new FileAppender();
appender.setFileName(...);
appender.setLayout(...);
Logger logger = Logger.getLogger("com.company.job."+jobName);
logger.addAppender(appender);

我们的系统中也实现了类似的东西。我们将特定的记录器存储在 HashMap 中,并根据需要为每个记录器初始化附加程序。

这是一个例子:

public class JobLogger {
private static Hashtable<String, Logger> m_loggers = new Hashtable<String, Logger>();
private static String m_filename = "...";  // Root log directory

public static synchronized void logMessage(String jobName, String message)
{
    Logger l = getJobLogger(jobName);
    l.info(message);
}

public static synchronized void logException(String jobName, Exception e)
{
    Logger l = getJobLogger(partner);
    l.info(e.getMessage(), e);
}

private static synchronized Logger getJobLogger(String jobName)
{
    Logger logger = m_loggers.get(jobName);
    if (logger == null) {
        Layout layout = new PatternLayout("...");
        logger = Logger.getLogger(jobName);
        m_loggers.put(jobName, logger);
        logger.setLevel(Level.INFO);
        try {
            File file = new File(m_filename);
            file.mkdirs();
            file = new File(m_filename + jobName + ".log");
            FileAppender appender = new FileAppender(layout, file.getAbsolutePath(), false);
            logger.removeAllAppenders();
            logger.addAppender(appender);
    }
        catch (Exception e)
    { ... }
    }
    return logger;
}
}

然后,要在工作中使用它,您只需使用一行条目,如下所示:

JobLogger.logMessage(jobName, logMessage);

这将为每个作业名称创建一个日志文件,并将其放入您指定的目录中具有该作业名称的自己的文件中。

您可以摆弄其他类型的附加程序等,正如所写的,它将继续附加,直到 JVM 重新启动,如果您在始终运行的服务器上运行相同的作业,这可能无法工作,但这给出了它如何进行的一般概念工作。

您可以为每个作业设置 NDC 或 MDC,然后编写一个根据 NDC 或 MDC 值改变名称的附加程序。创建一个新的附加程序并不难。可能还有一个适合 log4j 沙箱的附加程序。开始寻找 http://svn.apache.org/viewvc/logging/log4j/trunk/contribs/

您可以编写自己的附加程序来组成自己的文件名,也许使用 [File.createTempFile](http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html#createTempFile(java.lang.String,%20java.lang.String)) 方法。如果 FileAppender 类写得正确,你应该能够扩展它——或者 RollingFileAppender——并覆盖 getFile 方法返回您根据要添加的任何新属性选择的属性。

建立在 沙迪特的回答。如果每个作业都可以通过哪个类的 main 方法启动来识别,则可以使用系统属性 sun.java.command 包含开始的课程的全名。比如像这样:

log4j.appender.LOGFILE.File=${sun.java.command}.log

我将它与 时间戳文件追加器 像这样:

log4j.appender.LOGFILE=TimestampFileAppender
log4j.appender.LOGFILE.TimestampPattern=yyyy_MM_dd__HH_mm
log4j.appender.LOGFILE.File=${sun.java.command}_{timestamp}.log

这样,当我在 Eclipse 中进行开发时,我会为运行的每个新进程获取一个新的日志文件,该文件由带有 main 方法的类的类名及其启动时间来标识。

汤姆,您可以为每个作业指定和附加程序。假设您有 2 个作业对应于两个不同的 java 包 com.tom.firstbatch 和 com.tom.secondbatch,您将在 log4j.xml 中看到如下内容:

   <category name="com.tom.firstbatch">
      <appender-ref ref="FIRST_APPENDER"/>
   </category>
   <category name="com.tom.secondtbatch">
      <appender-ref ref="SECOND_APPENDER"/>
   </category>

您可以在初始化作业时以编程方式配置 log4j。

您还可以在运行时通过系统属性设置 log4j.properties 文件。来自 手动的:

将资源字符串变量设置为 log4j.配置 系统属性。指定默认初始化文件的首选方法是通过 log4j.configuration 系统属性。如果系统属性 log4j.configuration 未定义,则将字符串变量资源设置为其默认值“log4j.properties”。

假设您从不同的 java 命令运行作业,这将使它们能够使用不同的 log4j.properties 文件和每个作业的不同文件名。

如果不具体了解您的工作是如何运作的,就很难说!

您可以执行以下操作:

  • 一个 ThreadLocal 持有者,代表你的工作身份。
  • 扩展 FileAppender,您的 FileAppender 必须为每个作业身份保留一个包含 QuietWriter 的 Map。在 subAppend 方法中,您从 ThreadLocal 获取作业的标识,查找(或创建)QuietWriter 并写入它......

如果您愿意,我可以通过邮件向您发送一些代码...

log4j.logger.com.foo.admin =,adminfileappender log4j.logger.com.foo.report =,reportfileappender

这是完成这项任务的另一种方式..这里 com.foo.admin 是完整的包名称

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top