Инициализация Log4j по умолчанию выполняет процедуру поиска и использования URL-адреса для настройки с участием. Как впоследствии узнать, какой URL-адрес в конечном итоге использовался, без необходимости самостоятельно кодировать ту же процедуру? (Если вам нужно кодировать его самостоятельно, вы можете не получить его точно так же, как log4j, а также он может измениться в будущем выпуске.)
Как узнать, какой URL-адрес использовался при инициализации log4j по умолчанию?
Ответы (4)
Если вы хотите использовать AspectJ LTW (переплетение во время загрузки), вы можете взглянуть на статическую инициализацию LogManager
, упомянутую Яном Робертсом. В log4j 1.2.14 это выглядит так:
static {
// (...)
// if there is no default init override, then get the resource
// specified by the user or the default config file.
if (override == null || "false".equalsIgnoreCase(override)) {
// (...)
URL url = null;
// (...)
// If we have a non-null url, then delegate the rest of the
// configuration to the OptionConverter.selectAndConfigure method.
if (url != null) {
LogLog.debug("Using URL [" + url + "] for automatic log4j configuration.");
OptionConverter.selectAndConfigure(
url, configuratorClassName, LogManager.getLoggerRepository()
);
} else {
LogLog.debug("Could not find resource: [" + configurationOptionStr + "].");
}
}
}
Очевидно, что если можно определить URL-адрес по умолчанию, то OptionConverter.selectAndConfigure(URL, ..)
будет вызываться в одном месте внутри статического блока, чтобы инициализировать log4j с помощью этого URL-адреса.
С помощью AspectJ довольно просто перехватить вызов этого метода:
import java.net.URL;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.LogManager;
public aspect Log4jAspect {
before(URL defaultURL) :
within(LogManager) &&
cflow(staticinitialization(LogManager)) &&
call(* OptionConverter.selectAndConfigure(URL, ..)) &&
args(defaultURL, ..)
{
System.out.println("log4j default URL = " + defaultURL);
}
}
В прозе этот код означает:
- Если мы находимся в классе LogManager и
- в потоке управления инициализацией статического класса и
OptionConverter.selectAndConfigure
называется,- затем зафиксируйте первый аргумент (URL-адрес) и
- выведите его на консоль (с тем же успехом вы могли бы сделать что-то еще).
Если URL-адрес по умолчанию отсутствует, ничего не будет напечатано. Вместо того, чтобы печатать URL-адрес, вы можете назначить его статическому члену любого класса или тому, что вам нравится.
Это решение вашей проблемы, я проверил его, и он работает. Я был бы рад получить вознаграждение за ответ на ваш вопрос, даже если в решении используется технология, о которой вы не думали. Но это решает проблему. :-)
Изменить: также можно явно перехватить вызов журнала в случае, если URL-адрес по умолчанию не найден, хотя я не думаю, что это необходимо. Я просто хотел упомянуть об этом.
Используемая процедура жестко закодирована в статическом блоке инициализатора в LogManager
, поэтому, похоже, нет способа подключиться к ней. Единственное место, где он говорит вам, что происходит, это
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
но сам LogLog
жестко закодирован для использования System.out.println
для этих сообщений, поэтому единственная возможность, которую я вижу, - это включить отладку (-Dlog4j.debug=true
) и каким-то образом подключиться к System.setOut
до инициализации log4j, а затем проанализировать сообщение журнала отладки. Но это, вероятно, еще более хрупко, чем самостоятельное кодирование процедуры конфигурации.
Даже в этом случае после процедуры настройки по умолчанию (например, Spring Log4jConfigListener
) могла быть применена другая программная конфигурация (например, Spring Log4jConfigListener
) — не обязательно существует единый URL-адрес конфигурации как таковой.
Возможно, стоит поместить запрос функции log4j, чтобы выделить код поиска файла конфигурации в статический метод, который вы можете вызывать из другого места, но это не поможет, когда вам, возможно, придется справляться с более ранними версиями log4j.
Если вы можете настроить свой собственный конфигуратор, вы можете сделать что-то вроде этого:
Настройте системное свойство JAVA: -Dlog4j.configuratorClass=MyConfigurator И затем ваш экземпляр конфигуратора перехватит вызов doConfigure.
public class MyConfigurator implements Configurator
{
public static URL url;
@Override
public void doConfigure(URL url, LoggerRepository repository)
{
this.url = url;
new PropertyConfigurator().doConfigure(url, repository);
}
}
Вставьте это в свой вызов Java:
-Dlog4j.configDebug=true
Это все.