Как получить регистратор для подкласса?

У меня есть подкласс и суперкласс. В суперклассе у меня есть метод, который записывает что-то. Когда я создаю экземпляр подкласса, регистратор создает сообщение о регистрации для суперкласса. Почему это происходит?

Пример кода:

SuperClass.java

import java.util.logging.Level;
import java.util.logging.Logger;

public abstract class SuperClass {
    public void logAndPrintClass(){
        String name = this.getClass().getName();
        System.out.println(name);
        Logger logger = Logger.getLogger(name);
        logger.log(Level.INFO, "Logmessage");
    }
}

SubClass.java

public class SubClass extends SuperClass {
}

TestLogBubClass.java

public class TestLogBubClass {

    public static void main(String[] args){
        SuperClass obj = new SubClass();
        obj.logAndPrintClass();
    }
}

Вывод:

SubClass
Mar 15, 2013 6:30:04 PM SuperClass logAndPrintClass
INFO: Logmessage

Как вы можете видеть, имя класса правильно напечатано, но неправильно представлено в сообщении журнала.

Ответ 1

Эта причина в JavaDoc для LogRecord:

Обратите внимание, что если клиентское приложение не указало явное имя исходного метода и имя исходного класса, тогда класс LogRecord будет вызывать их автоматически при первом доступе (из-за вызова getSourceMethodName или getSourceClassName) путем анализа стека вызовов.

В этом случае стек вызовов заканчивается методом, определенным SuperClass, поэтому LogRecord предполагает, что он вызывает класс. Если вы хотите увидеть это в действии, выполните этот код:

public class Example {

    public static class Superclass {
        public void foo() {
            new Exception().printStackTrace();
        }
    }

    public static class Subclass extends Superclass {
        // nothing here
    }

    public static void main(String[] argv)
    throws Exception
    {
        Superclass s = new Subclass();
        s.foo();
    }
}

Изменить: я не использую j.u.l, но надеялся, что будет простой способ настройки вывода (как и в любой другой реализации регистратора). Похоже, вам придется реализовать свой собственный класс Formatter и указать его с помощью свойства java.util.logging.ConsoleHandler.formatter.

Я бы порекомендовал, если возможно, переключиться на SLF4J. Вы можете подключить весь существующий код j.u.l через SLF4J к фактическому регистратору, который дает вам больше контроля над его выходом (например, Log4J или Logback).

Ответ 2

Этот код java.util.logging довольно странный. Ведение журнала не использует name, но пытается выяснить сам исходный класс (который затем регистрируется). Изучите метод private void inferCaller() в классе java.util.logging.LogRecord.

Ответ 3

@Parsifal объяснил, почему это происходит, я попытаюсь объяснить обходной путь.

Если вы хотите увидеть точный класс, где вызывается метод, я бы рекомендовал использовать log4j или slf4j. Если вам нужно использовать java.util.Logger, пожалуйста, посмотрите jul-to-slf4j.

Я пробовал и для меня с теми же вводами ввода в моем стандартном выпуске выглядит следующим образом:

SubClass

15 марта 2013 г. 20:39:44 SuperClass logAndPrintClass

INFO: Logmessage

20: 39: 44 478 INFO SubClass: 12 - Logmessage

И в лог файле есть только:

20: 39: 44 478 INFO SubClass: 12 - Logmessage

Это может выглядеть не так хорошо, но в некоторых случаях это может быть подходящим решением.

Ответ 4

Я думаю, что у меня есть обходное решение, даже если я не могу дать полное объяснение.

Переопределение logAndPrintClass с помощью только вызова super, как это, в SubClass:

class SubClass extends SuperClass {
    protected void logAndPrintClass(){ super.logAndPrintClass(); }
}

Я все равно получаю тот же результат.

SubClass
Mar 15, 2013 11:22:10 AM SuperClass logAndPrintClass
INFO: Logmessage

Затем я просто скопировал тело метода в подкласс:

class SubClass extends SuperClass {
    protected void logAndPrintClass(){
        String name = this.getClass().getName();
        System.out.println(name);
        Logger logger = Logger.getLogger(name);
        logger.log(Level.INFO, "Logmessage");
    }
}

Затем я получил другой вывод:

SubClass
Mar 15, 2013 11:23:31 AM SubClass logAndPrintClass

Я не знаю, почему это работает, но единственная разница, которую я, кажется, обнаруживаю, заключается в том, что объект Logger теперь создается внутри подкласса, а не внутри суперкласса.