2016-02-23 2 views
3

Я создал новый обработчик журнала для JUL, который расширяет java.util.logging.Handler.Вход в обработчик журнала JUL

Есть ли стандартизованный способ, как я могу реагировать на ошибки, возникающие во время обработки LogRecord (например, LogLog в log4j)?

Просто используя JUL-Logger, вы получите другой LogRecord, который должен обрабатываться одним и тем же обработчиком.

Итак, я в основном ищу (стандартный) способ записи сообщений без создания бесконечного цикла. На данный момент я сравниваю sourceClassName, чтобы предотвратить такой цикл.

ответ

0

На данный момент я собираюсь для этого решения:

public class MyHandler extends Handler { 
    private final static String className = MyHandler.class.getName(); 
    private final static Logger logLogger = Logger.getLogger(className); 
    ... 

    @Override 
    public void publish(LogRecord record) { 
    if (!super.isLoggable(record)) { 
     return; 
    } 

    String loggerName = record.getLoggerName(); //EDIT: Was getSourceClassName before 
    if (loggerName != null && loggerName.equals(className)) { 
     // This is our own log line; returning immediately to prevent endless loops 
     return; 
    } 

    try { 
     // ... do actual handling... 
    } catch(Exception e) { 
     logLogger.logp(level.SEVERE, className, "publish", "something went wrong", e); 
    } 
    } 
} 
+0

Я бы не сбивал ThreadLocal, поскольку getSourceClassName() может прибегать к stackwalking, когда не использует logp. Если вы действительно уверены, что хотите указать только один источник, вместо этого используйте getLoggerName. – jmehrens

+0

@jmehrens: Вы абсолютно правы. Кажется, что ThreadLocals кажется более дешевым ... – Roman

+0

Существует еще одно решение: вместо вызова getSourceClassName() я мог бы также вызвать getLoggerName(), который не проходит через стек. Это кажется самым быстрым решением (если я не ** снова ** ошибаюсь ;-)) – Roman

1

Исключения, которые происходят внутри обработчика, следует сообщать с использованием Handler.reportError(String, Exception, int). Это сообщает об ошибках установленному ErrorManager, который можно настроить. Использование этого должно позаботиться о большинстве бесконечных циклов.

Однако, если публикация основана на lib, которая также генерирует записи журнала, вам необходимо прибегнуть к обнаружению цикла. Используйте java.lang.ThreadLocal и своего рода перечисление для отслеживания изменений состояния.

public class HandlerReentrance extends Handler { 

    private static final Level PUBLISH = Level.ALL; 
    private static final Level REPORT = Level.OFF; 

    private static final ThreadLocal<Level> LOCAL = new ThreadLocal<>(); 

    @Override 
    public void publish(LogRecord record) { 
     if (LOCAL.get() == null) { 
      LOCAL.set(PUBLISH); 
      try { 
       doPublish(record); 
      } finally { 
       LOCAL.remove(); 
      } 
     } else { 
      final Level last = LOCAL.get(); 
      if (PUBLISH.equals(last)) { 
       LOCAL.set(REPORT); 
       try { 
        reportLoop(record); 
       } finally { 
        LOCAL.set(last); 
       } 
      } 
     } 
    } 

    private void doPublish(LogRecord record) { 
     if (isLoggable(record)) { 
      //Insert code. 
     } 
    } 

    private void reportLoop(LogRecord record) { 
     //Insert code. 
    } 

    @Override 
    public void flush() { 
    } 

    @Override 
    public void close() { 
    } 
} 
+0

Каковы крайние случаи? –

+0

@ geoffrey-wiseman Если вы создаете обработчик для библиотеки lib с инфраструктурой регистрации/отладки. В этом случае обработчик привязан к регистратору, и в результате публикации используется lib, который, в свою очередь, использует API протоколирования. Мой опыт работы с JavaMail и MailHandler, но такой же тип событий произойдёт с JDBC API и DbHandler – jmehrens

+0

Спасибо за указание Handler.reportError (String, Exception, int). Я взглянул на реализацию и не был слишком доволен этим. Он просто печатает ошибку в System.err. Вариант ThreadLocal, по-видимому, является хорошим решением, за исключением стоимости (с точки зрения производительности) обработки ThreadLocals в целом. Я думаю, что поеду на SourceClassName. Таким образом, сообщение журнала может быть отправлено всем другим обработчикам. – Roman

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