2014-01-29 3 views
2

Чтобы инициализировать Log4j внутри класса, программисту необходимо предоставить экземпляр Class (или имя строки, которое представляет его). Код будет выглядеть так:Почему Log4j требуется имя класса?

public class MyClass { 
    private static Log logger = Logger.getLogger(MyClass.class); 
    [...] 
} 

Log4j затем предоставит выход на основе параметров, заданных программистом. Результат будет выглядеть примерно так:

[INFO] [MyClass:124] Foobar 

Мой вопрос: если Log4j знает, что номер строки заявления лесозаготовительной является(), то почему это нужно имя класса (MyClass)? Мне кажется, что если он сможет выяснить первое, он должен уметь выяснить последнее.

Редактировать: Это тоже не проблема; большинство из нас видели код, где программист случайно копирует и вставляет код инициализации из другого класса, но забывает изменить имя класса в инициализаторе. Это приводит к тому, что Log4j создает запутанный вывод.

(Конечно, в моем вопросе не указана конкретная проблема, но мне полезно понять, как работают Log4j и, возможно, отражение Java).

ответ

0

Чтобы решить проблему «копировать и макароны», попробуйте использовать метод GetClass() в коде так, когда вы скопировать и вставить декларацию регистратора к новому классу, он использует свое собственное имя класса, например, так:

private Logger log = Logger.getLogger(this.getClass()); 

Log4j на самом деле вызовет имя .getName() для имени класса, чтобы оно имело имя строки, используемое для регистратора. Фактически, вы можете поместить любую строку там, но соглашение должно использовать имя класса.

Может быть также использован случай, когда вы хотите использовать логгер класса A внутри класса B. Возможно, B является подклассом или частью внутреннего класса, и вы хотите, чтобы ваш результат ведения журнала выглядел так, будто он поступает из одного и того же имени журнала (имя класса). Пример:

public class MyClassB extends MyClassA { 
    private static Log logger = Logger.getLogger(MyClassB.class); 
    [...] 
} 
+0

Первое решение не работает при использовании статического регистратора, который необходим в статических классах. Второй момент, который вы сделали: не вызовет ли проблем с номером строки в таких регистраторах? И почему бы не использовать метод по умолчанию, который инициализируется вызывающим классом? – patstuart

+0

1. Правильно, это не будет работать для статического класса. 2. Это зависит от того, как ваш формат выводит ваш журнал. Номер строки исходит из исходного имени файла. Но включение номера строки «чрезвычайно медленно» (http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html). 3. Да, вы могли бы это сделать. – brandonjsmith

1

Для того, чтобы инициализировать Log4j внутри класса, программист должен предоставить экземпляр класса (или имя строки, которая представляет его).

Нет, это не требуется использовать имя класса - это только конвенции, так что вы можете настроить лесозаготовительной классом и имя пакета. Вы можете также использовать

private static Log logger = Logger.getLogger("SomeUniqueName"); 

Имя класса и номер строки извлекаются во время регистрации, скорее всего, извлекается через StackTrace текущего потока, который является узким местом производительности - см http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html.

Например, для L рисунка, он говорит

ПРЕДУПРЕЖДЕНИЕ Генерирование информация о местоположении вызывающего абонента происходит крайне медленно и следует избегать, если скорость выполнения не является проблемой.

Оставляя в стороне производительность получения трассировки стека, технически следующий также будет работать, чтобы получить как статические и экземпляра регистраторы без явной ссылки на класс (возможно, требует более сложной обработки ошибок, особенно с доступ к массиву):

public class ClassLogger { 
    public static Logger getLogger() { 
     String className = Thread.currentThread().getStackTrace()[2].getClassName(); 
     return Logger.getLogger(className); 
    } 
} 

Это может быть использован как

public class SomeClass { 
    private static Logger sl = ClassLogger.getLogger(); 
    private Logger il = ClassLogger.getLogger(); 

    ... 

Это будет в lso работают в режиме без отладки, так как имя класса также доступно в этом случае (в то время как имя файла и номер строки нет).

0

В общем случае экземпляру регистратора просто нужно имя.

Организационно разработчики определяют один экземпляр регистратора для каждого класса и используют имя класса в качестве имени регистратора. Чтобы использовать это обычное использование, log4j добавил метод фабрики удобства, который принимает экземпляр класса вместо String.

java.util.logging не предлагает этот метод удобства (что может быть причиной того, что его использование низкое, несмотря на то, что оно включено в JDK).

Чтобы избежать ошибок при копировании, вы можете попробовать использовать Lombok, который дает вам аннотацию, которая будет делать voodoo, и вводит правильно написанный статический экземпляр журнала во время компиляции (и управляет вашими шашками проверки кода статического кода).

Если вы можете выйти из языка Java, Groovy предлагает похожие AST transformation annotations.

Смежные вопросы