我们有几个同时运行的作业,它们必须为log4j使用相同的配置信息。他们都使用相同的附加程序将日志转储到一个文件中。有没有一种方法可以让每个作业动态命名其日志文件,以使它们保持独立?
谢谢
汤姆
您可以为每个作业传递Java系统属性吗?如果是这样,您可以像这样进行参数化:
1
| java -Dmy_var=somevalue my.job.Classname |
然后在您的log4j.properties中:
1
| log4j.appender.A.File=${my_var}/A.log |
您可以使用主机环境(例如)中的值填充Java系统属性,该值将唯一地标识作业的实例。
我们在系统中实现了类似的功能。我们将特定的记录器存储在HashMap中,并根据需要为每个记录器初始化附加器。
这里是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| 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;
}
} |
然后要在您的工作中使用它,您只需要使用如下一行即可:
1
| JobLogger.logMessage(jobName, logMessage); |
这将为每个作业名称创建一个日志文件,并将其放入您指定的目录中的该作业名称所在的文件中。
您可以摆弄其他类型的附加程序,例如,它将继续附加,直到重新启动JVM为止,如果您在始终启动的服务器上运行相同的作业,则可能无法正常工作,但这给出了以下基本概念:它如何工作。
如果提前知道作业名称,则可以在执行getLogger()调用时包括作业名称。然后,您可以使用不同的文件名(或其他目标)将不同的附加程序绑定到不同的记录器。
如果您无法提前知道作业名称,则可以在运行时配置记录器,而不使用配置文件:
1 2 3 4 5
| FileAppender appender = new FileAppender();
appender.setFileName(...);
appender.setLayout(...);
Logger logger = Logger.getLogger("com.company.job."+jobName);
logger.addAppender(appender); |
您可以为每个作业设置NDC或MDC,然后编写一个根据NDC或MDC值更改名称的附加程序。创建一个新的附加程序并不难。在log4j沙箱中可能还会有一个适合该帐单的附加程序。开始在http://svn.apache.org/viewvc/logging/log4j/trunk/contribs/
中查找
基于shadit的答案。如果可以通过启动哪个类的主方法来标识每个作业,则可以使用包含已启动类的全名的系统属性sun.java.command。例如这样的:
1
| log4j.appender.LOGFILE.File=${sun.java.command}.log |
我将它与TimestampFileAppender一起使用,如下所示:
1 2 3
| log4j.appender.LOGFILE=TimestampFileAppender
log4j.appender.LOGFILE.TimestampPattern=yyyy_MM_dd__HH_mm
log4j.appender.LOGFILE.File=${sun.java.command}_{timestamp}.log |
这样,当我在Eclipse中进行开发时,我为我运行的每个新进程都获得了一个新的日志文件,该文件由具有main方法的类的类名及其启动时间标识。
您可以编写自己的附加程序来组成自己的文件名,也许可以使用[File.createTempFile](http://java.sun.com/j2se/1.5.0/docs/api/java/io/File .html#createTempFile(java.lang.String,java.lang.String))方法。如果FileAppender类编写正确,则您应该能够扩展itor RollingFileAppender并覆盖getFile方法,以根据要添加的任何新属性返回您选择的方法。
log4j.logger.com.foo.admin =,AdminFileAppender
log4j.logger.com.foo.report =,ReportFileAppender
这是执行此任务的另一种方法。.com.foo.admin是完整的程序包名称。
您可以实现以下内容:
-
一个ThreadLocal持有人,用于确定您的工作身份。
-
扩展FileAppender,您的FileAppender必须为每个作业标识保留一个包含QuietWriter的Map。在方法subAppend中,您可以从ThreadLocal获取作业的标识,然后查找(或创建)QuietWriter并将其写入...
如果您愿意,我可以通过邮件向您发送一些代码...
您可以为每个作业指定和添加汤姆。假设您有2个作业,分别对应于两个不同的Java包com.tom.firstbatch和com.tom.secondbatch,在log4j.xml中您将拥有类似的内容:
1 2 3 4 5 6
| <category name="com.tom.firstbatch">
</category>
<category name="com.tom.secondtbatch">
</category> |
您可以在初始化作业时以编程方式配置log4j。
您还可以在运行时通过系统属性设置log4j.properties文件。从手册:
Set the resource string variable to the value of the log4j.configuration system property. The preferred way to specify the default initialization file is through the log4j.configuration system property. In case the system property log4j.configuration is not defined, then set the string variable resource to its default value"log4j.properties".
假设您正在通过不同的Java命令运行作业,这将使它们能够对每个作业使用不同的log4j.properties文件和不同的文件名。
没有关于您的工作如何运行的具体知识,很难说!