Как узнать, какой URL-адрес использовался при инициализации log4j по умолчанию?

Инициализация Log4j по умолчанию выполняет процедуру поиска и использования URL-адреса для настройки с участием. Как впоследствии узнать, какой URL-адрес в конечном итоге использовался, без необходимости самостоятельно кодировать ту же процедуру? (Если вам нужно кодировать его самостоятельно, вы можете не получить его точно так же, как log4j, а также он может измениться в будущем выпуске.)


person skiphoppy    schedule 28.08.2012    source источник


Ответы (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-адрес по умолчанию не найден, хотя я не думаю, что это необходимо. Я просто хотел упомянуть об этом.

person kriegaex    schedule 30.08.2012
comment
Ваши ответы фантастически информативны. Спасибо. Отличный способ подойти к чему-то, что, по-видимому, нельзя сделать именно так, как хотелось бы. - person skiphoppy; 04.09.2012
comment
›1000 повторений в день. впечатляет :р - person Matthias; 05.09.2012

Используемая процедура жестко закодирована в статическом блоке инициализатора в 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.

person Ian Roberts    schedule 30.08.2012

Если вы можете настроить свой собственный конфигуратор, вы можете сделать что-то вроде этого:

Настройте системное свойство 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);
    }
}
person Marc Polizzi    schedule 03.09.2012
comment
Это наводит на другую умную идею: переопределить конфигуратор, вставив свой собственный ранее в путь к классам... - person skiphoppy; 04.09.2012

Вставьте это в свой вызов Java:

-Dlog4j.configDebug=true

Это все.

person Mirko    schedule 31.08.2012
comment
Я ищу способ, чтобы моя программа могла найти эту информацию. - person skiphoppy; 31.08.2012