自定义注解实现logback配置按名称打印日志

首先是目录结构

目录结构图

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds" debug="false">
    <!--    &lt;!&ndash;引用公共日志&ndash;&gt;-->
    <include resource="logback/logback-base.xml"/>

    <!--    &lt;!&ndash; 开发环境配置 &ndash;&gt;-->
    <springProfile name="dev">
        <!-- 引用开发环境日志配置 -->
        <include resource="logback/logback-dev.xml"/>
    </springProfile>


    <!--    &lt;!&ndash; 生产环境配置 &ndash;&gt;-->
    <springProfile name="prod">
        <!-- 引用生产环境日志配置 -->
        <include resource="logback/logback-prod.xml"/>
    </springProfile>

</configuration>

logback-base.xml

<included>
<!--    最大文件大小-->
    <springProperty name="LOGGER_FILE_MAX_SIZE" scope="context" source="logback.filesize" defaultValue="5MB"/>
<!--     文件最大保存时间-->
    <springProperty name="LOGGER_FILE_MAX_DAY" scope="context" source="logback.filemaxday" defaultValue="2"/>
<!--    日志保留地址-->
    <property name="LOGGER_FILE_PATH" value="logs"/>
    <!--日志编码-->
    <property name="CHARSET" value="utf-8"/>
    <!-- 最大保留文件容量 -->
    <property name="TOTAL_SIZE_CAP" value="1GB" />

<!--    日志输出格式-->
    <property name="LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wex}"/>

    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
</included>

logback-dev.xml

<included>
    <property name="DEV_LOGGER_LEVEL" value="DEBUG"/>

    <!-- 控制台彩色日志格式 -->
    <property name="CONSOLE-LOG-PATTERN"
              value="%red(%date{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %red([%thread]) %boldMagenta(%logger{50}) %cyan(%msg%n)"/>

    <appender name="stdoutAppender" class="ch.qos.logback.core.ConsoleAppender">
        <withJansi>true</withJansi>
        <encoder>
            <pattern>${CONSOLE-LOG-PATTERN}</pattern>
            <charset>${CHARSET}</charset>
        </encoder>
    </appender>

    <appender name="console-async-appender" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="stdoutAppender"/>
    </appender>

    <root level="${DEV_LOGGER_LEVEL}" additivity="false">
        <appender-ref ref="console-async-appender"/>
    </root>

</included>

logback-prod.xml

<included>

    <property name="PROD_LOGGER_LEVEL" value="INFO"/>

    <appender name="data-appender-error" class="ch.qos.logback.classic.sift.SiftingAppender">
        <discriminator>
            <key>jobName</key>
            <defaultValue>system</defaultValue>
        </discriminator>

        <sift>
            <appender name="${jobName}-error" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <encoder>
                    <pattern>${LOG_PATTERN}</pattern>
                    <charset>${CHARSET}</charset>
                </encoder>
                <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                    <fileNamePattern>${LOGGER_FILE_PATH}/${jobName}.%d{yyyy-MM-dd}.%i.error</fileNamePattern>
                    <maxHistory>${LOGGER_FILE_MAX_DAY}</maxHistory>
                    <maxFileSize>${LOGGER_FILE_MAX_SIZE}</maxFileSize>
                    <totalSizeCap>${TOTAL_SIZE_CAP}</totalSizeCap>
                    <cleanHistoryOnStart>true</cleanHistoryOnStart>
                </rollingPolicy>
                <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                    <level>ERROR</level>
                </filter>
            </appender>
        </sift>
    </appender>

    <appender name="data-appender-info" class="ch.qos.logback.classic.sift.SiftingAppender">
        <discriminator>
            <key>jobName</key>
            <defaultValue>system</defaultValue>
        </discriminator>

        <sift>
            <appender name="${jobName}-info" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <encoder>
                    <pattern>${LOG_PATTERN}</pattern>
                    <charset>${CHARSET}</charset>
                </encoder>
                <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                    <fileNamePattern>${LOGGER_FILE_PATH}/${jobName}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                    <maxHistory>${LOGGER_FILE_MAX_DAY}</maxHistory>
                    <maxFileSize>${LOGGER_FILE_MAX_SIZE}</maxFileSize>
                    <totalSizeCap>${TOTAL_SIZE_CAP}</totalSizeCap>
                    <cleanHistoryOnStart>true</cleanHistoryOnStart>
                </rollingPolicy>
                <filter class="ch.qos.logback.classic.filter.LevelFilter">
                    <!--过滤 Error-->
                    <level>ERROR</level>
                    <!--匹配到就禁止-->
                    <onMatch>DENY</onMatch>
                    <!--没有匹配到就允许-->
                    <onMismatch>ACCEPT</onMismatch>
                </filter>
            </appender>
        </sift>
    </appender>

    <appender name="file_async" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="data-appender-info"/>
    </appender>

    <appender name="error_file_async" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="data-appender-error"/>
    </appender>

    <logger name="根路径" level="error" additivity="false">
        <appender-ref ref="error_file_async"/>
    </logger>

    <logger name="根路径" level="${PROD_LOGGER_LEVEL}" additivity="false">
        <appender-ref ref="file_async"/>
    </logger>

    <root level="${PROD_LOGGER_LEVEL}">
        <appender-ref ref="file_async"/>
        <appender-ref ref="error_file_async"/>
    </root>
</included>

最后是注解的实现,技术是logback的Mdc,只要任务在同一个线程内就可以实现日志区分

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MdcLogger {
    /**
     * logger MDC对应的value值
     * @return
     */
    String value();

}

Aop的实现

@Aspect
@Component
public class MdcLoggerAspect {

    private static Logger logger = LoggerFactory.getLogger(MdcLoggerAspect.class);

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.lz.bigdata.synchronizer.biz.dy.domain.annotation.MdcLogger)")
    public void mdcLoggerCutPoint() {
        logger.info("MDC切入点");
    }

    @Before("mdcLoggerCutPoint()")
    public void mdcLoggerBefore(JoinPoint joinPoint) {
        MdcLogger mdcLoggerAnnotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getDeclaredAnnotation(MdcLogger.class);
        String value = mdcLoggerAnnotation.value();
//        String methodName = joinPoint.getTarget().getClass().getSimpleName() + "." + joinPoint.getSignature().getName();
        MDC.put(配置文件定义的名称(此文章是jobName), value);
    }

    @After("mdcLoggerCutPoint()")
    public void mdcLoggerAfter() {
        MDC.clear();
    }
}


版权声明:本文为weixin_43836438原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。