logback:两个追加器、多个记录器、不同级别



我想在我的应用程序(Spring Integration)中有两个日志文件,debug.log和main.log。 我想在信息级别运行main.log并在调试级别进行调试.log。 这可以通过附加器上的过滤器来实现。 我想根据源将不同的级别记录到追加器。 换句话说,

<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. 弹簧记录仪
    • 主 -> 错误
    • 调试 -> 调试
  2. com.myapp logger
    • 主要 ->信息
    • 调试 -> 调试

因此,我必须让记录器在 DEBUG 上运行,并且追加器上的阈值过滤器不够细粒度。

更新 增加了问题的清晰度

创建一个 ThresholdLoggerFilter 类,该类可以放在附加器上,如下所示:

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

添加比此处已有的解决方案更简单的其他解决方案

这些解决方案都不适合我,因为我没有使用像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 语句输出到日志文件。

如果您愿意从根记录器继承,您也可以更轻松地执行此操作,例如,在这里我们为错误添加一个额外的记录器,该记录器记录到 stderr。它仅对特定记录器启用。

<configuration>
    <appender name="CONSOLE-stdout" class="ch.qos.logback.core.ConsoleAppender">
        <target>System.out</target> <!-- the default -->
        <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>

刚刚找到了一个仅使用logback元素的实用解决方案,该解决方案运行良好,基本上您需要有两个附加器,一个具有默认配置,另一个带有过滤器(在我的示例中,我正在使用控制台):

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

对不同的消息使用多个记录器将是这样的:

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

追加器上的阈值筛选器不够细粒度

您可以使用评估器筛选器。 JaninoEventEvaluator 需要引用 janino (.jar) 和 logback.xml示例为:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>INFO</level>
    </filter>
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">      
        <evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
            <expression>
                level &lt;= ERROR &amp;&amp; logger.equals(&quot;com.myapp.ThresholdLoggerFilter&quot;)
            </expression>
        </evaluator>
        <OnMismatch>DENY</OnMismatch>
        <OnMatch>NEUTRAL</OnMatch>
    </filter>
 </appender>

此方法在表达式标记中使用 java 表达式(必须进行 xml 转义)来评估日志记录事件,并且不需要编写自定义 java 类。

相关内容

最新更新