2013-06-04 9 views
42

Mam append z logbackem zdefiniowany w logback.xml, jest to aplikacja dostarczająca DB, ale jestem ciekawy, czy istnieje jakikolwiek sposób skonfigurowania appendera w języku Java za pomocą własnej puli połączeń zdefiniowanej jako komponent bean.Programowo skonfiguruj applikującego LogBacka

Znajduję podobne rzeczy, ale nigdy rzeczywistej odpowiedzi.

Odpowiedz

87

Oto prosty przykład, który pracuje dla mnie (zauważ, że używam FileAppender w tym przykładzie)

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: Mógłbyś zaznaczyć w komentarzu, co chciałbyś zmienić w aktualnej wersji. Spróbuję go odpowiednio zaktualizować. – reto

+0

@reto Moja zmiana głównie (1) dodaje deklarację klasy tak, że kompiluje się tak jak jest i (2) dodaje brakującą "g" do "Logera". –

+1

Dzięki za wejście. Zaktualizowałem te rzeczy. – reto

14

Programistów można skonfigurować programowo. Niemal wszyscy aplikanci są testowani przy użyciu programowej konfiguracji. Wynika z tego, że istnieje wiele przykładów konfiguracji programisty appendera w kodzie źródłowym projektu logback. W przypadku aplikacji dostarczającej rdzeń typu logback-core spójrz pod numer logback-core/src/test/java, a następnie spójrz na klasycznego append pod numerem logback-classic/src/test/java.

2

Podobnie, jeśli ktoś szuka konkretnego przykładu programowej konfiguracji.

Tu setup charset od 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")); 

A moja 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> 

Dlaczego muszę programmaticaly skonfigurować rejestrator? Ponieważ pakuję swoją aplikację (Spring Boot) do pliku JAR. W związku z tym plik Logback.xml wygląda na ukryty w słoiku. Jednak nie jest wygodne rozpakowywanie i zmienianie go. I nie trzeba żadnego pliku logback.xml obok mojego app.jar. Mam tylko plik app.yaml, który zawiera wszystkie właściwości konfiguracji aplikacji.

3

Podczas próby modyfikacji kodu odpowiedzialnego za tworzenie rejestratorów, istnieje kilka reguł, które muszą być spełnione, aby rejestrator działał.

Te zasady zostały opisane w wielkim i pomocny artykuł Programmatic configuration of slf4j/logback:

Teraz mam doświadczenie z konfiguracją programową SLF4J/logback.

Zadanie

program musi otworzyć oddzielny plik dziennika dla każdego pliku wejściowego przetwarzane.

rozwiązanie dla zadania

Zamiast konfigurowania logback poprzez XML, jeden musi „ręcznie” instancję koderów appenders i rejestratory, a następnie skonfigurować i połączyć je ze sobą.

Zastrzeżenie 1

Logback szaleje na próbę podzielenia koder (tj PatternLayoutEncoder) pomiędzy appenders.

rozwiązanie dla zastrzeżeniem 1

Tworzenie osobnego kodera dla każdego appender.

Zastrzeżenie 2

Logback odmawia niczego zalogować, jeśli koderów i appenders nie są związane z kontekstem logowania.

rozwiązanie dla zastrzeżeniem 2

połączeń setContext na każdej kodera i appender, przechodząc LoggerFactory jako parametr.

Zastrzeżenie 3

Logback odmawia niczego zalogować, jeśli koderów i appenders nie są uruchamiane.

Roztwór do zastrzeżeniem 3

koderów i appenders muszą być uruchomione we właściwej kolejności, to znaczy pierwsze koderów następnie appenders.

Zastrzeżenie 4

obiekty RollingPolicy (tj TimeBasedRollingPolicy) wytwarzają dziwne komunikaty o błędach, takich jak „format daty nie uznane”, gdy nie są one przyłączone do tego samego kontekstu jako appender.

rozwiązanie dla zastrzeżeniem 4

wezwanie setContext na RollingPolicy sam sposób, jak na koderów i appenders.

Oto przykład „Manual” konfiguracji logback pracy:

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

Nie wolno komentować (jeszcze?) Chciałbym tylko dodać trzy wskazówki;

  • dotyczące zastrzeżenia, wyżej, jeśli masz problemy, wystarczy dodać wywołanie

    StatusPrinter.print(context); 
    

    po wszystko zostało skonfigurowane, czyli po dodaniu swojej appenders root/„main” appender: to będzie powiedzieć, co jest nie tak.

  • Bardzo lubię rozdzielać poziomy rejestrowania w różnych plikach; przy poszukiwaniu błędów Zacznę patrząc w pliku błędów i tak dalej, mając je ustawić jak

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

routingu za pomocą prostego prywatnej klasie filtra takiego jak

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; 
      } 
     } 
    } 

, a następnie po prostu zadzwoń pod numer myFilter.start() i myAppender.addFilter(myFilter);.

  • Wreszcie wprowadzenie go razem, zazwyczaj chcą mieć możliwość zmiany poziomu dziennika dynamicznie mający konfiguracja wdrożyć jakiś prosty interfejs jak

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

utrzymując poziom rejestrowania korzeniowy w niektórych nieruchomości -plik, który jest monitorowany, tak że zawsze, gdy jest jakiś poprawny sygnał wejściowy, po prostu wywołuję tę usługę zaimplementowaną jak

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

z moim nowym poziomem rootgera.

Powiązane problemy