从Spring-Boot开始深入理解Spring系列(三)——Spring-Boot集成主流java的log框架-logback和log4j2

版权声明:本文为博主原创文章,大家喜欢的话,多多转载吧! https://blog.csdn.net/u011500356/article/details/85411764

引言:

对于java中,使用日志,估计大多数人一听就是很懵逼。认识比较片面,而且对于各种概念很模糊。尤其是对于日志的最佳实践,充满着各种稀奇古怪的习惯。本文,借助Spring-boot 集成主流java日志框架,logback和log4j2,给大家做一个简单的示例。

先有一个直观的代码印象,如果大家有兴趣想要更深地了解日志的最佳实践。请移步我的另一篇博客《Java专家之路(六)—日志知识体系的总结–以java程序中的日志为例》

想随意切换,集成主流java日志框架的实现?

这个需求,实现很简单,依赖并使用日志门面框架slf4J进行编程,而不是依赖具体的日志框架。如:logback、log4j、log4j2等

想在不同环境,使用不同的日志配置 ?

spring-boot提供了一种很简单的日志配置标签< springProfile >,支持多环境的日志配置。如下所示

	<!-- 测试环境 -->
	<springProfile name="test">
		<!-- 每天产生一个文件 -->
		<appender name="TEST-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
			<!-- 文件路径 -->
			<file>${TEST_FILE_PATH}</file>
			<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
				<!-- 文件名称 -->
				<fileNamePattern>${TEST_FILE_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
				<!-- 文件最大保存历史数量 -->
				<MaxHistory>100</MaxHistory>
			</rollingPolicy>
			
			<layout class="ch.qos.logback.classic.PatternLayout">
				<pattern>${PATTERN}</pattern>
			</layout>
		</appender>
		
		<root level="info">
			<appender-ref ref="TEST-FILE" />
		</root>
	</springProfile>

	<!-- 生产环境 -->
	<springProfile name="prod">
		<appender name="PROD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
			<file>${PRO_FILE_PATH}</file>
			<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
				<fileNamePattern>${PRO_FILE_PATH}/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
				<MaxHistory>100</MaxHistory>
			</rollingPolicy>
			<layout class="ch.qos.logback.classic.PatternLayout">
				<pattern>${PATTERN}</pattern>
			</layout>
		</appender>
		<logger name="com.dynamic.springbootlogback" level="info"/>
		<root level="warn">
			<appender-ref ref="PROD_FILE" />
		</root>
	</springProfile>

想知道,日志的最佳实践 ?

  • 不同环境,不同的配置。
    *开发环境:
    *测试环境:
    *生产环境:
  • 按类型(级别),将日志分类输出
  • 定期清理
  • 日志严格执行合理正确的分级
  • 自定义日志输出格式
  • 伺机而动(把握记录日志的时机)
  • 警惕性能陷阱(日志,少而精)

想在spring-boot下优雅地打印日志(AOP)?

在我们的程序中,有很多的日志,例如:异常日志、入参值和返回值都很重要,是程序运行调试的重要依据和参考。而且,应该在每个方法上都要记录,那么问题就来了。这样的系统日志,重复的代码,如何优雅地处理?

答案是:我们可以使用AOP,实施面向切面的编程。将这种和业务无关的代码,剥离到一个切面类中。通过动态代理的方式,织入到我们的代码当中来。以此来增强我们的目标方法。

想利用SLF4j的MDC机制,定制日志输出格式和内容 ?

MDC,是什么?Mapped Diagnostic Context,映射调试上下文。是 log4j 和 logback 提供的,一种方便在多线程条件下记录日志的功能。

很多时候,日志框架并不能提供足够多的有用的信息,以辅助我们进行更好的定位问题。

需求一:排查问题用得最多的方式是查看日志,但是在现有系统中,各种无关日志穿行其中,导致我没办法快速的找出用户在一次请求中所有的日志。我们想要在所有的日志标准输出内容中,加上session_id , 或者user_id 等业务相关的日志信息。

需求二:想要快速过滤一次请求的所有日志,并通过装饰器模式使得MDC工具在异步线程里也能生效。有了MDC,再通过AOP技术对所有的切面植入requestId,就可以将整个系统的任意流程的日志过滤出来。

MDC代码片段一:

备注:put值到threadlocal(MDC的实现,使用的就是threadlocal)中,所以出于线程安全和使用规范考虑,一定要在线程结束后,及时清除线程变量。

 @Before("weblog()")
    public void doBefore(JoinPoint joinPoint) {
        //target
        LOGGER.debug("进入前置通知:dorBefore方法");
        //记录请求的内容:
        // 请求的IP,方式,url,
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest req = attributes.getRequest();
        // 解析请求报文,使用MDC,打印日志,也可在前置通知中获取
        MDC.put("SESSION_ID", req.getSession().getId());
        MDC.put("IP", req.getRemoteAddr());
        MDC.put("URL", req.getRequestURL().toString());

        Object[] objects = joinPoint.getArgs();

        Signature signature = joinPoint.getSignature();
        LOGGER.debug("signature ={}", signature.toString());
        LOGGER.debug("方法:{}", signature.getName());
        LOGGER.debug("方法所在的类:{}", signature.getDeclaringType());
        LOGGER.debug("方法所在的包:{}", signature.getDeclaringTypeName());

        MethodSignature methodSignature = (MethodSignature) signature;
        String[] parameterNames = methodSignature.getParameterNames();
        LOGGER.debug("方法参数的名字:{}", Arrays.toString(parameterNames));
        LOGGER.debug("方法的参数的值:{}", Arrays.toString(objects));


        LOGGER.debug("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());


        //wave

    }

MDC代码片段二:清理线程变量MDC中的值

 @After("weblog()")
        public void doAfter(JoinPoint joinPoint) {
        LOGGER.debug("whatever happened i very execute finally !");
        MDC.clear();

    }

配置示例:

<!-- console专用 日志内容输出格式 -->
	<property name="PATTERN-CONSOLE" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) %highlight(|-%-5level) [%thread] [%X{URL}] [%X{IP}] [%X{SESSION_ID}] %c %cyan([%L-]) | %msg%n" />

想要自定义日志的格式?炫酷的个性化颜色?

logback提供了对日志内容的格式自定义的强大支持,包括自定义颜色字体、内容等。
注意:只能在console控制台使用

<!-- console专用 日志内容输出格式 -->
	<property name="PATTERN-CONSOLE" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) %highlight(|-%-5level) [%thread] [%X{URL}] [%X{IP}] [%X{SESSION_ID}] %c %cyan([%L-]) | %msg%n" />

本文源码下载

https://github.com/bill4j/spring-boot-course/tree/develop/spring-boot-logconfig

查看更多相关博客:

java编程日志的最佳实践参考一

最佳实践参考二:

最佳实践参考三:

猜你喜欢

转载自blog.csdn.net/u011500356/article/details/85411764