У нас есть несколько задач, которые выполняются одновременно и должны использовать одну и ту же информацию о конфигурации для log4j. Все они выгружают журналы в один файл, используя один и тот же аппендер. Есть ли способ, чтобы каждое задание динамически именовало свой файл журнала, чтобы они оставались отдельными?
Спасибо Том




Вы можете программно настроить 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 и разные имена файлов для каждого из них.
Без конкретных знаний о том, как выполняется ваша работа, трудно сказать!
Вы можете указать и дополнения для каждой работы. Предположим, у вас есть 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>
Если имена заданий известны заранее, вы можете включить имя задания при выполнении вызова getLogger (). Затем вы можете привязать разные приложения к разным регистраторам с разными именами файлов (или другими местами назначения).
Если вы не можете заранее узнать имя задания, вы можете настроить регистратор во время выполнения вместо использования файла конфигурации:
FileAppender appender = new FileAppender();
appender.setFileName(...);
appender.setLayout(...);
Logger logger = Logger.getLogger("com.company.job."+jobName);
logger.addAppender(appender);
Можете ли вы передать системное свойство Java для каждого задания? Если это так, вы можете параметризовать следующим образом:
java -Dmy_var=somevalue my.job.Classname
А затем в вашем log4j.properties:
log4j.appender.A.File=${my_var}/A.log
Вы можете заполнить системное свойство Java значением из среды хоста (например), которое однозначно идентифицирует экземпляр задания.
Вы можете написать свой собственный аппендер, который составляет свое собственное имя файла, возможно, используя метод [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, чтобы верните тот, который вы выберете на основе любых новых свойств, которые вы хотите добавить.
Вы можете настроить каждое задание NDC или MDC, а затем написать приложение, имя которого будет варьироваться в зависимости от значения NDC или MDC. Создать новый аппендер не так уж сложно. В песочнице log4j также может быть приложение, которое будет соответствовать всем требованиям. Начать поиск в http://svn.apache.org/viewvc/logging/log4j/trunk/contribs/
вы можете реализовать следующее:
Если хотите, я могу отправить вам код по почте ...
У нас в системе реализовано нечто подобное. Мы храним определенные регистраторы в 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, что может не работать, если вы запустите то же задание на сервере, который всегда включен, но это дает общее представление о том, как это можно работай.
log4j.logger.com.foo.admin =, AdminFileAppender log4j.logger.com.foo.report =, ReportFileAppender
Это еще один способ выполнить эту задачу .. здесь com.foo.admin - полное имя пакета
Основываясь на ответе шадит. Если каждое задание можно определить по тому, главный метод какого класса был запущен, вы можете использовать системное свойство sun.java.command, которое содержит полное имя запущенного класса. Например, вот так:
log4j.appender.LOGFILE.File=${sun.java.command}.log
Я использую его вместе с TimestampFileAppender вот так:
log4j.appender.LOGFILE=TimestampFileAppender
log4j.appender.LOGFILE.TimestampPattern=yyyy_MM_dd__HH_mm
log4j.appender.LOGFILE.File=${sun.java.command}_{timestamp}.log
Таким образом, когда я разрабатываю в Eclipse, я получаю новый файл журнала для каждого нового процесса, который я запускаю, идентифицируемый именем класса с основным методом и временем его запуска.