vlambda博客
学习文章列表

千万项目Logback项目使用总结

前言

Logback是一个开源的日志组件,SpringBoot中现在内置的也是logback日志框架,可以看出来它的地位,本篇文章主要就是介绍logback的上产使用配置等,以及一些比较重要的解决方案,本文中的文件直接就可以上生产使用。

1.logstash直接配置在logback:

logback是可以支持直接配置logstash的ip和端口进行推送的,类似于阿里云的日志推送。当然如果考虑到量大的的话可以采用filebeat直接推送es, 通过定义pipeline.json来进行创建索引,也可以采用filebeat-》logstash(解决索引问题)-》es,当然也可以加入通过其他的kafka中间件等。下面文件是logstash的logback中的配置文件,修改对应的ip和端口即可。

<?xml version="1.0" encoding="UTF-8"?><included>
 
<!-- 将日志打印到控制台 -->
    <appender name="PROJECT-CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern> %d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
 
<!-- 将日志写入到文件配置 -->
    <appender name="PROJECT-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logging.path}/application.log</file>
        <encoder >
            <pattern>"host": "%ip" %d{HH:mm:ss.SSS} %-5level [%thread] %logger{32}[%file:%line] -&gt; %msg%n</pattern>
            <charset class="java.nio.charset.Charset">UTF-8</charset>
        </encoder>
<!--配置备份 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logging.path}/application.log.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
    </appender>
 
<!-- logback 和 logstash 通讯配置 -->
    <appender name="SOCKET" class="net.logstash.logback.appender.LogstashSocketAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <host>${logstash.host}</host>
        <port>${logstash.port}</port>
    </appender>
 
    <!-- logstash远程日志配置-->
    <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>${logstash.host}:${logstash.port}</destination>
<!--输出打印json格式-->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        <!--输出日志可自定义,可根据自己需要配置-->
                        {                        <!--es索引名称 -->
                        "indexname":"test_logstash",                        <!--应用名称 -->
                        "appname":"${spring.application.name}",                        <!--服务器ip -->
                        "host": "%ip",                        <!--应用端口 -->
                        "port": "${spring.application.index}",                        <!--打印时间 -->
                        "timestamp": "%d{yyyy-MM-dd HH:mm:ss.SSS}",                        <!--线程名称 -->
                        "thread": "%thread",                        <!--日志级别 -->
                        "level": "%level",                        <!--日志名称 -->
                        "logger_name": "%logger",                        <!--日志信息 -->
                        "message": "%msg",                        <!--日志堆栈 -->
                        "stack_trace": "%exception"
                        }                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
 
    <root level="INFO">
        <appender-ref ref="PROJECT-FILE"/>
        <appender-ref ref="PROJECT-CONSOLE"/>
        <appender-ref ref="SOCKET"/>
        <appender-ref ref="LOGSTASH"/>
    </root>
 </included>

2.经典应用日志级别划分、日期、大小分割等

生产项目的配置文件logback.xml:

<?xml version="1.0" encoding="UTF-8"?><configuration>
    <!-- 项目名称,需修改 -->
    <property name="applicationName" value="xxx"/>
    <!-- 日志存储格式 -->
 
<property name="pattern"
              value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{12} %5p [%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}] %X{traceId} %X{userId} %msg%n"/>
    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%logger){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>


    <!--控制台 appender-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!--encoder 默认配置为PatternLayoutEncoder-->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level -&#45;&#45; [%thread] %logger Line:%-3L - %msg%n</pattern>-->
            <charset>utf-8</charset>
        </encoder>
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
    </appender>

    <!--错误 appender-->
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>logs/error.log</File>
        <!-- 过滤器,只记录ERROR级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${pattern}</pattern>
        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>logs/error.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--最长保存5天-->
            <MaxHistory>15</MaxHistory>
            <CleanHistoryOnStart>true</CleanHistoryOnStart>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>

    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>logs/warn.log</File>
        <!-- 过滤器,只记录WARN级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder charset="UTF-8">
            <pattern>${pattern}</pattern>
            <charset>utf-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>logs/warn.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <MaxHistory>15</MaxHistory>
            <CleanHistoryOnStart>true</CleanHistoryOnStart>
            <TimeBasedFileNamingAndTriggeringPolicy  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </TimeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>

    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>logs/info.log</File>
        <!-- 过滤器,只记录INFO级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${pattern}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>logs/info.%d{yyyy-MM-dd}.log</FileNamePattern>
            <MaxHistory>15</MaxHistory>
            <CleanHistoryOnStart>true</CleanHistoryOnStart>
        </rollingPolicy>
    </appender>

    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>logs/debug.log</File>
        <!-- 过滤器,只记录DEBUG级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${pattern}</pattern>
            <charset>utf-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>logs/debug.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <TimeBasedFileNamingAndTriggeringPolicy  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>150MB</maxFileSize>
            </TimeBasedFileNamingAndTriggeringPolicy>
            <MaxHistory>15</MaxHistory>
            <CleanHistoryOnStart>true</CleanHistoryOnStart>
        </rollingPolicy>
    </appender>

    <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>logs/trace.log</File>
        <!-- 过滤器,只记录ERROR级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>TRACE</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${pattern}</pattern>
            <charset>utf-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>logs/trace.%d{yyyy-MM-dd}.log</FileNamePattern>
            <MaxHistory>15</MaxHistory>
            <CleanHistoryOnStart>true</CleanHistoryOnStart>
        </rollingPolicy>
    </appender>

    <!--异步配置-->
    <appender name="ASYNC-STDOUT" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <neverBlock>true</neverBlock>
        <!-- 控制台输出 -->
        <appender-ref ref="STDOUT"/>
    </appender>
    <!--异步配置-错误-->
    <appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <neverBlock>true</neverBlock>
        <!-- 错误日志输出 -->
        <appender-ref ref="ERROR"/>
    </appender>
    <!--异步配置-INFO-->
    <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <neverBlock>true</neverBlock>
        <!--info级别-->
        <appender-ref ref="INFO"/>
        <!--warn级别-->
        <appender-ref ref="WARN"/>
    </appender>
  
    <logger name="slf4j" level="INFO"/>
    <!-- 测试环境+开发环境. 多个使用逗号隔开. -->
    <!-- 控制台输出 -->
    <springProfile name="dev">
        <root level="INFO">
           
             <!-- 控制台输出 -->
           <appender-ref ref="STDOUT"/>
            <!-- 文件输出 -->
            <appender-ref ref="ERROR"/>
            <appender-ref ref="INFO"/>
            <appender-ref ref="WARN"/>
            <!--<appender-ref ref="WARN"/>-->

        </root>
    </springProfile>
    <springProfile name="test">
        <root level="INFO">
            <!-- 控制台输出 -->

            <!-- 文件输出 -->
            <appender-ref ref="ERROR"/>
            <appender-ref ref="INFO"/>
            <appender-ref ref="WARN"/>

        </root>
    </springProfile>

    <springProfile name="pre">
        <root level="INFO">
            <!-- 控制台输出 -->

            <!-- 文件输出 -->
            <appender-ref ref="ERROR"/>
            <appender-ref ref="INFO"/>
            <appender-ref ref="WARN"/>

        </root>
    </springProfile>

    <!-- 生产环境. -->
    <springProfile name="prod">
        <root level="INFO">
            <!-- 文件输出 -->
            <appender-ref ref="ERROR"/>
            <appender-ref ref="INFO"/>
            <appender-ref ref="WARN"/>

        </root>
    </springProfile></configuration>

3.异步配置及使用

为什么要使用异步,就是为了性能的提升,异步参数的配置也能在一定程度上在日志量很大的时候节省性能的开销。异步配置就是在 同步appender的基础之上增加异步appender进行配置即可。

<!--异步配置-->
    <appender name="ASYNC-STDOUT" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <neverBlock>true</neverBlock>
        <!-- 控制台输出 -->
        <appender-ref ref="STDOUT"/>
    </appender>
    <!--异步配置-错误-->
    <appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <neverBlock>true</neverBlock>
        <!-- 错误日志输出 -->
        <appender-ref ref="ERROR"/>
    </appender>
    <!--异步配置-INFO-->
    <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <neverBlock>true</neverBlock>
        <!--info级别-->
        <appender-ref ref="INFO"/>
        <!--warn级别-->
        <appender-ref ref="WARN"/>
    </appender>
    <!--异步配置-WARN-->
    <appender name="ASYNC-WARN" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <neverBlock>true</neverBlock>
        <!--warn级别-->
        <appender-ref ref="WARN"/>
    </appender>

    <logger name="slf4j" level="INFO"/>
    <!-- 测试环境+开发环境. 多个使用逗号隔开. -->
    <!-- 控制台输出 -->
    <springProfile name="dev">
        <root level="INFO">
            <!--使用异步配置日志 ASYNC -->
            <!--<appender-ref ref="ASYNC-STDOUT"/>-->
            <!-- 文件输出 -->
            <appender-ref ref="ASYNC-ERROR"/>
            <appender-ref ref="ASYNC-INFO"/>
            <appender-ref ref="ASYNC-WARN"/>
           

        </root>
    </springProfile>

异步参数配置说明:

属性名 类型 描述
queueSize int BlockingQueue的最大容量,默认情况下,大小为256
discardingThreshold int 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0
includeCallerData boolean 提取调用者数据的代价是相当昂贵的。为了提升性能,默认情况下,当event被加入到queue时,event关联的调用者数据不会被提取。默认情况下,只有"cheap"的数据,如线程名

4.总结

上面就是loback的生产项目实战总结,当然很多地方可能没具体的写详细。毕竟logback还有很多细节的地方可以进行优化,包括MDC的使用等等,但是总体上来说上面的配置已经能够胜任大型的上产项目的应用,欢迎大家进行交流。