【问题标题】:Customizing log level display in with logback and logstash-logback encoder使用 logback 和 logstash-logback 编码器自定义日志级别显示
【发布时间】:2015-12-26 10:54:21
【问题描述】:

我正在使用 logstash-logback-encoder 以 json 格式打印日志。

我的logback.xml 如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <includeContext>false</includeContext>
            <fieldNames>
                <timestamp>timestamp</timestamp>
                <version>[ignore]</version>
                <levelValue>[ignore]</levelValue>
            </fieldNames>
        </encoder>
    </appender>
    <appender name="stash"
        class="ch.qos.logback.core.rolling.RollingFileAppender">        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/tmp/SolrUpdater.%d{yyyy-MM-dd}.log
            </fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <includeContext>false</includeContext>
            <fieldNames>
                <timestamp>timestamp</timestamp>
                <version>[ignore]</version>
                <levelValue>[ignore]</levelValue>
            </fieldNames>
        </encoder>
    </appender>
    <root level="error">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="stash" />
    </root>
</configuration>

谁能告诉我如何将所有level 显示为小写,如error,而不是默认的ERRORWARNwarning

更新 - 我按照 Zakhar 的建议创建了一个 CustomLogLevelJsonProvider

package com.jabong.discovery.importer.solrUpdater.log;

public class CustomLogLevelJsonProvider extends LogLevelJsonProvider {
    final static String DEBUG = "debug";
    final static String ERROR = "error";
    final static String INFO = "info";
    final static String WARNING = "warning";

    @Override
    public void writeTo(JsonGenerator generator, ILoggingEvent event)
        throws IOException {
    JsonWritingUtils.writeStringField(generator, getFieldName(),
        getCustomLogLevel(event));
    }

    private String getCustomLogLevel(ILoggingEvent event) {
    if (event.getLevel() == Level.ALL) {
        return Level.ALL.toString();
    }
    if (event.getLevel() == Level.DEBUG) {
        return DEBUG;
    }
    if (event.getLevel() == Level.ERROR) {
        return ERROR;
    }
    if (event.getLevel() == Level.INFO) {
        return INFO;
    }
    if (event.getLevel() == Level.WARN) {
        return WARNING;
    }
    return "";
    }
}

更新logback.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
         <encoder class="com.jabong.discovery.importer.solrUpdater.log.CustomEncoder">
            <includeContext>false</includeContext>
            <fieldNames>
                <timestamp>timestamp</timestamp>
                <version>[ignore]</version>
                <levelValue>[ignore]</levelValue>
            </fieldNames>
        </encoder>
    </appender>
    <appender name="FILE"
        class="ch.qos.logback.core.rolling.RollingFileAppender">        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/tmp/SolrUpdater.%d{yyyy-MM-dd}.log
            </fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <includeContext>false</includeContext>
            <fieldNames>
                <timestamp>timestamp</timestamp>
                <version>[ignore]</version>
                <levelValue>[ignore]</levelValue>
            </fieldNames>
        </encoder>
    </appender>
    <root level="error">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

现在我看到两个level

{"timestamp":"2015-12-26T23:41:08.818+05:30","message":"Partial Updater Initialization Failed ","logger_name":"com.jabong.discovery.importer.solrUpdater.partialupdate.PartialUpdater","thread_name":"main","level":"ERROR","stack_trace":"java.lang.Exception: Failed to Connect to SolrIndex Type:solr, Core:discovery, Host:localhost, Port:8888\n\tat com.jabong.discovery.importer.solrUpdater.partialupdate.PartialUpdater.initIndexUpdater(PartialUpdater.java:83) [classes/:na]\n\tat com.jabong.discovery.importer.solrUpdater.partialupdate.PartialUpdater.initialise(PartialUpdater.java:36) [classes/:na]\n\tat com.jabong.discovery.importer.solrUpdater.partialupdate.PartialUpdater.<init>(PartialUpdater.java:30) [classes/:na]\n\tat Updater.initialise(Updater.java:50) [classes/:na]\n\tat Updater.main(Updater.java:70) [classes/:na]\n","level":"error"}

【问题讨论】:

    标签: java log4j logback logstash-logback-encoder


    【解决方案1】:

    我不知道这是否可以通过 XML 进行配置。但我只是试图覆盖你不喜欢的行为。 您将需要实现两个新类。

    1)

    public class CustomEncoder extends LogstashEncoder {
        public CustomEncoder() {
            LoggingEventJsonProviders providers = getFormatter().getProviders();
    
            // Remove provider that is responsible for log level appending
            removeDefaultProvider(providers);
    
            // Register our implementation
            providers.addLogLevel(new CustomLogLevelJsonProvider());
        }
    
        private void removeDefaultProvider(LoggingEventJsonProviders providers) {
            JsonProvider<ILoggingEvent> providerToDelete = null;
    
            for (JsonProvider<ILoggingEvent> provider : providers.getProviders()) {
                if (provider instanceof LogLevelJsonProvider) {
                    providerToDelete = provider;
                    break;
                }
            }
    
            providers.removeProvider(providerToDelete);
        }
    }
    

    2)

    public class CustomLogLevelJsonProvider extends LogLevelJsonProvider {
        @Override
        public void writeTo(JsonGenerator generator, ILoggingEvent event) throws IOException {
            JsonWritingUtils.writeStringField(
                    generator, getFieldName(), event.getLevel().toString().toLowerCase());
        }
    }
    

    3) 在配置中启用新的编码器。

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="com.test.encoder.CustomEncoder">
            <includeContext>false</includeContext>
            <fieldNames>
                <timestamp>timestamp</timestamp>
                <version>[ignore]</version>
                <levelValue>[ignore]</levelValue>
            </fieldNames>
        </encoder>
    </appender>
    

    更新: 您已更新您的问题。您将需要一些额外的逻辑来将 WARN 或警告转换为警告。由于这将发生在每条日志消息上,这将产生开销。 您要更改的值在类中被硬编码:ch.qos.logback.classic.Level

    【讨论】:

    • 你能告诉我我必须在哪里放置这些自定义类吗?
    • 在你的类路径中。例如在您的项目中。
    • 我尝试了你的解决方案,但现在我看到两个 level 。一个具有价值ERROR,另一个具有价值error
    • 您是否对两个附加程序都使用了自定义编码器?
    • 尝试将自定义编码器添加到两个附加程序,并将其添加到控制台附加程序,但在两种情况下都看到相同的情况。日志中有两个 level 字段。
    【解决方案2】:

    最好使用 Logstash 并在“级别”字段上应用小写过滤器。

    【讨论】:

      【解决方案3】:

      我们可以在%level的基础上,使用logback的replace函数将INFO替换为info

      我们可以多次应用这个replace来处理所有级别的情况:

      "%replace(%replace(%replace(%replace(%level){'INFO','info'}){'WARN','warn'}){'ERROR','error'}){'DEBUG','debug'}"
      

      这为我们提供了“小写”级别:

      { "level": "info", "message": ... }
      

      【讨论】:

        猜你喜欢
        • 2020-01-19
        • 2015-11-25
        • 2016-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-21
        • 2016-08-20
        相关资源
        最近更新 更多