2013-06-04 3 views
42

У меня есть приложение logback, определенное в файле logback.xml, это приложение DB, но мне любопытно, есть ли способ настроить appender в java, используя мой собственный пул соединений, определенный как bean-компонент.Программно настроить приложение LogBack

Я нахожу похожие вещи, но не на самом деле отвечу.

ответ

87

Вот простой пример, который работает для меня (обратите внимание, что я использую FileAppender в этом примере)

import org.slf4j.LoggerFactory; 

import ch.qos.logback.classic.Level; 
import ch.qos.logback.classic.Logger; 
import ch.qos.logback.classic.LoggerContext; 
import ch.qos.logback.classic.encoder.PatternLayoutEncoder; 
import ch.qos.logback.classic.spi.ILoggingEvent; 
import ch.qos.logback.core.FileAppender; 

public class Loggerutils { 

    public static void main(String[] args) { 
      Logger foo = createLoggerFor("foo", "foo.log"); 
      Logger bar = createLoggerFor("bar", "bar.log"); 
      foo.info("test"); 
      bar.info("bar"); 
    } 

    private static Logger createLoggerFor(String string, String file) { 
      LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 
      PatternLayoutEncoder ple = new PatternLayoutEncoder(); 

      ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n"); 
      ple.setContext(lc); 
      ple.start(); 
      FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>(); 
      fileAppender.setFile(file); 
      fileAppender.setEncoder(ple); 
      fileAppender.setContext(lc); 
      fileAppender.start(); 

      Logger logger = (Logger) LoggerFactory.getLogger(string); 
      logger.addAppender(fileAppender); 
      logger.setLevel(Level.DEBUG); 
      logger.setAdditive(false); /* set to true if root should log too */ 

      return logger; 
    } 

} 
+0

@Andrew Swan: Не могли бы вы отметить в комментарии, что вы хотели бы изменить с текущей версией. Я попытаюсь обновить его соответствующим образом. – reto

+0

@reto Мое изменение в основном (1) добавляет объявление класса так, что оно компилируется как-is и (2) добавляет отсутствующий «g» в «Loger». –

+1

Спасибо за ввод. Я обновил эти вещи. – reto

14

Программные приложения можно настроить программно. Почти все приставки тестируются с использованием программной конфигурации. Из этого следует, что в исходном коде проекта logback имеется много примеров конфигурации программных приложений. Для приложения с поддержкой logback-core найдите под logback-core/src/test/java, а для журнала-классического appender посмотрите под logback-classic/src/test/java.

2

Просто, если бы кто-то ищет конкретный пример программной конфигурации.

Здесь я настроить кодировка ConsoleAppender:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 
ConsoleAppender<ILoggingEvent> appender = 
    (ConsoleAppender) lc.getLogger("appconsole").getAppender("STDOUT"); 
LayoutWrappingEncoder<ILoggingEvent> enc = 
    (LayoutWrappingEncoder<ILoggingEvent>) appender.getEncoder(); 
enc.setCharset(Charset.forName("utf-8")); 

И мой logback.xml:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
    <encoder> 
     <charset>866</charset> 
     <pattern>[%level] %msg%n</pattern> 
    </encoder> 
</appender> 

<logger name="appconsole"> 
    <appender-ref ref="STDOUT" /> 
</logger> 

Почему мне нужно programmaticaly настроить регистратор? Потому что я упаковываю свое приложение (Spring Boot) в файл jar. Следовательно, файл Logback.xml кажется скрытым внутри банки. Хотя, неудобно распаковывать и изменять его. И мне не нужен любой файл logback.xml рядом с моим app.jar. У меня есть только файл app.yaml, который содержит все свойства конфигурации для приложения.

3

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

Эти правила были описаны в большом и полезные статьи Programmatic configuration of slf4j/logback:

Теперь у меня есть опыт работы с программной конфигурацией SLF4J/Logback.

Задача

Программа должна открыть отдельный файл журнала для каждого обрабатываемого входного файла.

решение для задачи

Вместо настройки Logback с помощью XML, то нужно «вручную» инстанцирует кодеры, appenders и регистраторы, а затем настроить и связать их вместе.

Caveat 1

Logback сходит с ума при попытке разделить кодер (т.е. PatternLayoutEncoder) между appenders.

Раствор для предостережением 1

Создать отдельный кодер для каждого Appender.

Caveat 2

Logback отказывается что-нибудь войти, если кодеры и appenders не связаны с контекстом регистрации.

Раствор для предостережения 2

Вызова SetContext на каждый кодер и Appender, передавая LoggerFactory в качестве параметра.

Caveat 3

Logback отказывается что-нибудь войти, если кодеры и appenders не запускаются.

Раствора для предостережения 3

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

Caveat 4

RollingPolicy объекты (т.е. TimeBasedRollingPolicy) производят странное сообщение об ошибке, как «формат даты не распознан», когда они не прикреплены к одной и той же контексте, как Appender.

Раствор для предостережения 4

вызова SetContext на RollingPolicy точно так же, как и на кодеры и appenders.

Здесь работает пример «ручной» конфигурация Logback:

package testpackage 

import ch.qos.logback.classic.Level 
import ch.qos.logback.classic.Logger 
import ch.qos.logback.classic.LoggerContext 
import ch.qos.logback.classic.encoder.PatternLayoutEncoder 
import ch.qos.logback.core.ConsoleAppender 
import ch.qos.logback.core.rolling.RollingFileAppender 
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy 

import org.slf4j.LoggerFactory 

class TestLogConfig { 

    public static void main(String[] args) { 
    LoggerContext logCtx = LoggerFactory.getILoggerFactory() 

    PatternLayoutEncoder logEncoder = new PatternLayoutEncoder() 
    logEncoder.setContext(logCtx) 
    logEncoder.setPattern('%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n') 
    logEncoder.start() 

    ConsoleAppender logConsoleAppender = new ConsoleAppender() 
    logConsoleAppender.setContext(logCtx) 
    logConsoleAppender.setName('console') 
    logConsoleAppender.setEncoder(logEncoder) 
    logConsoleAppender.start() 

    logEncoder = new PatternLayoutEncoder() 
    logEncoder.setContext(logCtx) 
    logEncoder.setPattern('%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n') 
    logEncoder.start() 

    RollingFileAppender logFileAppender = new RollingFileAppender() 
    logFileAppender.setContext(logCtx) 
    logFileAppender.setName('logFile') 
    logFileAppender.setEncoder(logEncoder) 
    logFileAppender.setAppend(true) 
    logFileAppender.setFile('logs/logfile.log') 

    TimeBasedRollingPolicy logFilePolicy = new TimeBasedRollingPolicy() 
    logFilePolicy.setContext(logCtx) 
    logFilePolicy.setParent(logFileAppender) 
    logFilePolicy.setFileNamePattern('logs/logfile-%d{yyyy-MM-dd_HH}.log') 
    logFilePolicy.setMaxHistory(7) 
    logFilePolicy.start() 

    logFileAppender.setRollingPolicy(logFilePolicy) 
    logFileAppender.start() 

    Logger log = logCtx.getLogger("Main") 
    log.additive = false 
    log.level = Level.INFO 
    log.addAppender(logConsoleAppender) 
    log.addAppender(logFileAppender) 
    } 
} 
0

Не разрешено комментировать (пока?), Я просто хотел бы добавить три подсказки;

  • относительно к предостережениям выше, если у вас есть проблемы, просто добавьте вызов

    StatusPrinter.print(context); 
    

    после того как все было настроено, то есть, после того, как добавили appenders корень/«Main» appender: будет расскажет вам, что не так.

  • Мне очень нравится разделять уровни регистрации в разных файлах; при поиске ошибок я начинаю с поиском в файле ошибок и так далее, имея их настроить, как

tot_[app name].log : Level.INFO 
deb_[app name].log : Level.DEBUG 
err_[app name].log : Level.ERROR 

маршрутизация с помощью простого частного класса фильтра, такого как

private static class ThresholdLoggerFilter extends Filter<ILoggingEvent> { 

     private final Level level; 

     private ThresholdLoggerFilter(Level level){ 
      this.level = level; 
     } 

     @Override 
     public FilterReply decide(ILoggingEvent event) { 
      if (event.getLevel().isGreaterOrEqual(level)) { 
       return FilterReply.NEUTRAL; 
      } else { 
       return FilterReply.DENY; 
      } 
     } 
    } 

, а затем просто позвоните myFilter.start() и myAppender.addFilter(myFilter);.

  • И, наконец, положить его вместе, я обычно хочу, чтобы иметь возможность изменять уровень лога динамически имеющими настройки реализовать некоторые простой интерфейс, как

    public interface LoggingService { 
        void setRootLogLevel(Level level); 
    } 
    

сохраняя уровень протоколирования корня в некоторой собственности -file, который контролируется таким образом, что всякий раз, когда есть какой-то действительный ввод там, я просто вызываю эту услугу, как

@Override 
    public void setRootLogLevel(Level level) { 
     if (context != null && context.isStarted()) { 
     ((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level); 
     } 
    } 

с моим новым уровнем корневого регистратора.

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