2012-05-24 2 views
34

Я хочу иметь два файла журнала в моем приложении (Spring Integration), debug.log и main.log. Я хочу запустить main.log на уровне INFO и debug.log на уровне DEBUG. Это можно сделать с фильтрами в приложениях. Я хочу регистрировать различные уровни в приложениях на основе источника. Другими словамиlogback: два приложения, несколько регистраторов, разные уровни

<logger name="org.springframework" level="ERROR"> 
    <appender-ref ref="main" /> 
</logger> 
<logger name="org.springframework" level="DEBUG"> 
    <appender-ref ref="debug" /> 
</logger> 
<logger name="com.myapp" level="INFO"> 
    <appender-ref ref="main" /> 
</logger> 
<logger name="com.myapp" level="DEBUG"> 
    <appender-ref ref="debug" /> 
</logger> 

Итак, подведем итог:

  1. Весна регистратор
    • главная -> ОШИБКА
    • отладки -> DEBUG
  2. com.myapp регистратор
    • main - > INFO
    • отладки -> DEBUG

Из-за этого я должен иметь регистраторы, работающие в DEBUG и пороговый фильтр на к appender'у не отлично достаточно зернистой.

Update Добавлена ​​ясность в вопрос

ответ

39

Создать ThresholdLoggerFilter класс, который можно поставить на Appender как:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> 
     <level>INFO</level> 
    </filter> 
    <filter class="com.myapp.ThresholdLoggerFilter"> 
     <logger>org.springframework</logger> 
     <level>ERROR</level> 
    </filter> 
    </appender> 

Следующий код работает

package com.myapp; 

import ch.qos.logback.classic.Level; 
import ch.qos.logback.classic.spi.ILoggingEvent; 
import ch.qos.logback.core.filter.Filter; 
import ch.qos.logback.core.spi.FilterReply; 

public class ThresholdLoggerFilter extends Filter<ILoggingEvent> { 
    private Level level; 
    private String logger; 

    @Override 
    public FilterReply decide(ILoggingEvent event) { 
     if (!isStarted()) { 
      return FilterReply.NEUTRAL; 
     } 

     if (!event.getLoggerName().startsWith(logger)) 
      return FilterReply.NEUTRAL; 

     if (event.getLevel().isGreaterOrEqual(level)) { 
      return FilterReply.NEUTRAL; 
     } else { 
      return FilterReply.DENY; 
     } 
    } 

    public void setLevel(Level level) { 
     this.level = level; 
    } 

    public void setLogger(String logger) { 
     this.logger = logger; 
    } 

    public void start() { 
     if (this.level != null && this.logger != null) { 
      super.start(); 
     } 
    } 
} 
+1

Простой и чистый ответ! Этот пример был идеален для моих нужд !!! – araknoid

+4

Не нужно реализовывать себя, используйте ch.qos.logback.classic.filter.ThresholdFilter –

+2

ThresholdFilter просто фильтрует на пороге. Я хочу фильтровать как порог logger AND –

15

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

<configuration> 
    <appender name="CONSOLE-stdout" class="ch.qos.logback.core.ConsoleAppender"> 
     <target>System.out</target> 
     <encoder> 
      <pattern>%d %-5level [%thread] %logger{0}: %msg%n</pattern> 
     </encoder> 
    </appender> 
    <appender name="CONSOLE-stderr" class="ch.qos.logback.core.ConsoleAppender"> 
     <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> 
      <level>ERROR</level> 
     </filter> 

     <target>System.err</target> 
     <encoder> 
      <pattern>%d %-5level [%thread] %logger{0}: %msg%n</pattern> 
     </encoder> 
    </appender> 
    <root level="DEBUG"> 
     <appender-ref ref="CONSOLE-stdout" /> 
    </root> 

     <!-- We want error logging from this logger to go to an extra appender 
      It still inherits CONSOLE-stdout from the root logger --> 
    <logger name="org.springframework" level="INFO"> 
     <appender-ref ref="CONSOLE-stderr" /> 
    </logger> 
</configuration> 
+0

Спасибо @artbristol, но это не дает гранулярности управления, которого я хочу. Я обновил вопрос, чтобы показать, почему. –

0

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

import ch.qos.logback.classic.Level; 
import ch.qos.logback.classic.Logger; 

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 ConfigureLogBack 
{ 
    public static void programmaticConfiguration() 
    { 
     Logger camel = getLogger("MyRoute", C:\\Users\\amrut.malaji\\Desktop\\Oracle\\logback\\camel-Log.txt"); 
     Logger services = getLogger("webservices", "C:\\Users\\amrut.malaji\\Desktop\\Oracle\\logback\\services-log.txt"); 
    } 

    private static Logger getLogger(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.INFO); 
    logger.setAdditive(false); /* set to true if root should log too */ 

    return logger; 
} 
1

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

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
     <encoder> 
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> 
     </encoder> 
    </appender> 

    <appender name="WARN_FILTER_STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
     <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> 
      <level>WARN</level> 
     </filter> 
     <encoder> 
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> 
     </encoder> 
    </appender> 

    <logger name="org.apache.spark" level="INFO" additivity="false"> 
     <appender-ref ref="SPARK" /><!-- this line is not necessary, just here to ilustrate the need for the filter --> 
     <appender-ref ref="WARN_FILTER_STDOUT" /> 
    </logger> 

    <root level="info"> 
     <appender-ref ref="STDOUT" /> 
    </root> 
1

Добавление дополнительного решения, которое проще, чем то, что уже ее e

Ни один из этих решений не работал для меня, так как я не использую фреймворк, такой как Spark или Spring. Поэтому я сделал что-то более простое, что, похоже, прекрасно работает. Хотя это решение может не работать для OP, возможно, это может быть полезно для кого-то, желающего чего-то не столь громоздкого.

<property name="pattern" value="%d{yyyy.MMM.dd HH:mm:ss.SSS} [ProgramName] %level - %msg%n" /> 

<appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
    <file>/path/to/your/program.log</file> 
    <append>true</append> 
    <encoder> 
     <pattern>${pattern}</pattern> 
    </encoder> 
</appender> 

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
    <target>System.out</target> 
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> 
     <level>INFO</level> 
    </filter> 
    <encoder> 
     <pattern>${pattern}</pattern> 
    </encoder> 
</appender> 

<root level="debug"> 
    <appender-ref ref="FILE" /> 
    <appender-ref ref="STDOUT" /> 
</root> 

С этой конфигурацией я могу сохранить консоль довольно чистой при выводе операторов DEBUG в файл журнала.

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