Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >logback自定义日志格式

logback自定义日志格式

作者头像
全栈程序员站长
发布于 2022-08-15 13:22:28
发布于 2022-08-15 13:22:28
81400
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

logback自定义日志格式

1.ClassicConverter

继承ClassicConverter

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.demo.conf;
 
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
 
import java.net.InetAddress;
import java.net.UnknownHostException;
 
/** * 配置日志中显示IP */
public class IPLogConfig extends ClassicConverter { 
   
    @Override
    public String convert(ILoggingEvent event) { 
   
        try { 
   
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) { 
   
            e.printStackTrace();
        }
        return null;
    }
}

然后再logback.xml中配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!--配置规则类的位置-->
<conversionRule conversionWord="ip" converterClass="com.demo.conf.IPLogConfig" />
 <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <layout>
            <pattern>%ip -%date{HH:mm:ss} %highlight(%-5level)[%yellow(%thread)]%green(%logger{56}.%method:%L) -%msg%n"</pattern>
        </layout>
    </appender>

2.实现PropertyDefiner

logback提供自定义属性接口PropertyDefiner

实现PropertyDefiner:getPropertyValue()方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class GetIpProperty implements PropertyDefiner{ 
   
    @override
    public String getPropertyValue() { 
   
        try { 
   
                InetAddress address = InetAddress.getLocalHost();
                return address.getHostAddress();
 
          } catch (UnknownHostException e) { 
   
              e.printStackTrace();
          }   
               return null;
      }
   	//....
}

然后在logback.xml配置文件中,定义自定义标签define name代表标签,class指向处理的类。在初始化时调用getPropertyValue()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
	<define name="ip" class="com.lay.config.log.GetIpProperty"></define>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    	<encode>
        	<parttern>${ip}-%date{HH:mm:ss} %highlight(%-5level)[%yellow(%thread)]%green(%logger{56}.%method:%L) -%msg%n"</parttern>
        </encode>
    </appender>
</configuration>

3.SLF4JMDC

Logback是在logback-classic模块中实现了SLF4J的MDC功能。

MDC中管理的数据(简称MDC数据)是以单个线程为单位进行访问的,即对MDC数据的操作(如put, get)只对当前线程有效,所以也永远是线程安全的。 在服务端,为每个请求分配一个线程进行处理,所以每个服务端线程处理的请求,都具有唯一的MDC上下文数据。

子线程不会自动继承父线程的MDC数据。所以在创建子线程时,可以先调用MDC的getCopyOfContextMap()方法以返回一个Map<String, String>对象,从而获取父线程的MDC数据,然后再在子线程的开始处,最先调用MDC的setContextMap()方法为子线程设置父线程的MDC数据。从而能够在子线程中访问父线程的MDC数据。

在使用java.util.concurrent.Executors管理线程时,使用同样的方法让子线程继承主线程的MDC数据。

但是,在Web应用中,一个请求可能在不同的阶段被多个线程处理。这时,只是在服务端的处理线程中设置MDC数据,并不能保证请求的某些信息(如用户的认证信息等)总是能够被处理线程访问到。为了在处理一个请求时能够保证某些信息总是可访问,建议使用Servlet Filter,在请求到来时就将信息装入到MDC中,在完成所有的后续处理后,再次通过过滤器时将MDC数据移除。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	public class MyFilter implements Filter { 
   
		public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException { 
   
			...
			MDC.put(MY_KEY, myValue);
			...
		    try { 
   
			  chain.doFilter(request, response);
			} finally { 
   
			  if (MDC.contains(MY_KEY)) { 
   
				MDC.remove(MY_KEY);
			  }
			}

Logback自带的ch.qos.logback.classic.helpers.MDCInsertingServletFilter能够将HTTP请求的hostname, request URI, user-agent等信息装入MDC,只需在web.xml中设置(建议MDCInsertingServletFilter作为第一个Filter配置,原因请读者思考),后续处理过程就可以直接访问如下请求参数的值:

req.remoteHost req.xForwardedFor req.method req.requestURI req.requestURL req.queryString

req.userAgent

源码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.lay.log.core.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

/** * @Description: * @Author: lay * @Date: Created in 11:22 2019/3/19 * @Modified By:IntelliJ IDEA */
public class LogFilter implements Filter { 
   
    private static final Logger log = LoggerFactory.getLogger(LogFilter.class);


    @Override
    public void init(FilterConfig filterConfig) { 
   

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
   
        log.info("start log filter");
        this.insertIntoMDC(request);
        log.info("log filter....");
        try { 
   
            chain.doFilter(request, response);
        } finally { 
   
            log.info("log filter....");
            this.clearMDC();
            log.info("end log filter");
        }

    }

    void insertIntoMDC(ServletRequest request) { 
   
        MDC.put("req.remoteHost", request.getRemoteHost());
        if (request instanceof HttpServletRequest) { 
   
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            MDC.put("req.requestURI", httpServletRequest.getRequestURI());
            StringBuffer requestURL = httpServletRequest.getRequestURL();
            if (requestURL != null) { 
   
                MDC.put("req.requestURL", requestURL.toString());
            }
            String requestNo = httpServletRequest.getHeader("Request-No");
            if (requestNo != null && !requestNo.equals("")) { 
   
                MDC.put("req.requestNo", requestNo);
            }
            MDC.put("req.method", httpServletRequest.getMethod());
            MDC.put("req.queryString", httpServletRequest.getQueryString());
            MDC.put("req.userAgent", httpServletRequest.getHeader("User-Agent"));
            MDC.put("req.xForwardedFor", httpServletRequest.getHeader("X-Forwarded-For"));
            MDC.put("req.hostIp", getHostIp());
        }
    }

    void clearMDC() { 
   
        MDC.remove("req.remoteHost");
        MDC.remove("req.requestURI");
        MDC.remove("req.queryString");
        MDC.remove("req.requestURL");
        MDC.remove("req.method");
        MDC.remove("req.userAgent");
        MDC.remove("req.xForwardedFor");
        MDC.remove("req.requestNo");
        MDC.remove("req.ho stIp");
    }

    @Override
    public void destroy() { 
   

    }

    public String getHostIp() { 
   
        try { 
   
            InetAddress address = InetAddress.getLocalHost();
            return address.getHostAddress();

        } catch (UnknownHostException e) { 
   
            e.printStackTrace();
        }
        return null;
    }
}

配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
public class ApplicationConfig { 
   
    @Bean
    public FilterRegistrationBean filterRegistrationBean() { 
   
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        Filter actionFilter = new MDCInsertingServletFilter();
        registrationBean.setFilter(actionFilter);
        List<String> urlPatterns = new ArrayList<>();
        urlPatterns.add("/*");
        registrationBean.setUrlPatterns(urlPatterns);
        return registrationBean;
    }
}

使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <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(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>/>



    <property name="MDC_LOG_PATTERN" value="IP:%X{req.remoteHost} -url:%X{req.requestURI} -Method:%X{req.method} - QueryString:%X{req.queryString} - device:%X{req.userAgent} -ips:%X{req.xForwardedFor} - %m%n "></property>

    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <layout>
            <pattern>${MDC_LOG_PATTERN}</pattern>
        </layout>
    </appender>


    <root level="INFO">
        <appender-ref ref="Console"/>
        <!--<appender-ref ref="Sentry"/>-->
    </root>
</configuration>

可以看到 MDC_LOG_PATTERN 中获取了从MDC过滤器中的参数,这样我们就能打印出来了

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/134466.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring Boot入门系列(十三)统一日志处理!
前面介绍了Spring Boot 异常处理,今天主要讲解Spring Boot中的日志收集,日志是追踪错误定位问题的关键,特别在生产环境中,我们需要通过日志快速定位解决问题。
架构师精进
2020/06/17
2.4K0
手动实现 Spring Boot 日志链路追踪,无需引入组件,日志定位更方便!
有时候一个业务调用链场景,很长,调了各种各样的方法,看日志的时候,各个接口的日志穿插,确实让人头大。
芋道源码
2024/04/12
4360
手动实现 Spring Boot 日志链路追踪,无需引入组件,日志定位更方便!
跟我学Springboot开发后端管理系统8:AOP+logback+MDC日志输出
在比较复杂的应用中,一个请求需要走很多个方法的处理,怎么样才能快速查找一个请求的全部日志呢。在分布式系统中,我们可以用链路追踪,比如zipkin、skywalking去快速查找日志,从而定位问题。在比较复杂的单体管理系统中,我们可以使用slf4j的MDC去实现类似的功能。
方志朋
2022/01/06
7910
MDC是什么鬼?用法、源码一锅端
近期用到阿里的一款开源的数据同步工具 Canal,不经意之中看到了 MDC 的用法,而且平时项目中也多次用到 MDC,趁机科普一把。
一猿小讲
2020/04/21
4.3K0
MDC是什么鬼?用法、源码一锅端
聊聊springboot的logback配置
org/springframework/boot/logging/logback/defaults.xml
code4it
2023/10/31
7600
SpringBoot入门系列(十一)统一日志收集!
今天主要讲解Spring Boot中的日志收集,日志是追踪错误定位问题的关键,特别在生产环境中,我们需要通过日志快速定位解决问题。
架构师精进
2020/05/18
1.1K0
logback 配置日志输出到 logstash
发表于2018-06-062019-01-01 作者 wind <?xml version="1.0" encoding="UTF-8" ?> <configuration> <inclu
前Thoughtworks-杨焱
2022/02/19
1.3K0
Lombok @Slf4j 使用和配置
pom依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId>
鱼找水需要时间
2023/02/16
9120
SLF4J MDC ☞ 将用户信息添加到日志信息中
你是否有过排查某个用户的操作出现 BUG 时, 从茫茫日志中寻找这个用户操作的痛苦经历, SLF4J 为我们提供了一种基于 ThreadLocal 来实现的 MDC 功能, 用来将自定义信息放入到日志中.
一份执着✘
2019/12/30
1.2K0
SLF4J MDC ☞ 将用户信息添加到日志信息中
SpringBoot基础(三):Logback日志
适配器作用:以后想要换其他日志框架,只要排除掉logback日志实现,导入log4j2或jul的日志实现即可,代码中API还是slf4j不需要修改,只修改maven依赖就改变了日志的底层实现。
冬天vs不冷
2025/01/21
2370
SpringBoot基础(三):Logback日志
Just Do IT,你的SpringBoot日志输出格式,由你来定!
LogBack是默认集成在SpringBoot里面的,是基于Slf4j的日志框架。默认情况下,SpringBoot是按照INFO级别输出到控制台的。
是Vzn呀
2022/07/14
1.8K0
Just Do IT,你的SpringBoot日志输出格式,由你来定!
从头分析一则traceId穿透问题(附解决方案)
现在常用的开源组件有google的Dapper,Twitter的zipkin和Apache SkyWalking等,商用的比较有代表性的是阿里的Eagleeye(鹰眼)。它们的工作模式不外乎是客户端在同一个trace的不同span上采点上传到server端然后server端进行存储后以web界面的形式将整个链路以traceId和spanId进行关联起来就形成了整个调用链路。用于串起整个链路的id主要分为traceId和spanId。
山行AI
2020/09/24
5.9K3
从头分析一则traceId穿透问题(附解决方案)
SpringBoot 的 logback 日志配置
1. 在 resources 目录下创建日志的配置文件 logback-spring.xml , 这是 SpringBoot 官方约定的名称
北漂的我
2020/07/03
7710
Java 项目日志:从Logback到SLF4J,再到链路跟踪配置详解
Java 应用开发运维中,日志记录重要。本文探讨 Logback 与 SLF4J 使用方式,介绍如何实现链路跟踪功能,提升系统监控和问题排查能力。
Yeats_Liao
2025/01/07
3900
Java 项目日志:从Logback到SLF4J,再到链路跟踪配置详解
万字详解logback日志框架,再没这么全的了!
老项目中日志使用混乱,某些项目使用log4j,某些项目使用logback,统一是必须的。既然Spring Boot已经将logback做为默认集成的日志框架,全面了解学习是必然了。
程序新视界
2020/10/28
5.1K0
万字详解logback日志框架,再没这么全的了!
20201001_kpay支付项目搭建
如何快速的开始一个新项目,最高效的做法是复制一份现有生产环境的项目,修改一下包名称。这样代码是经过考验的,且很多基础功能的代码可以直接复用。
雨粒石
2020/10/10
1.4K0
SpringBoot——配置logback日志
介绍: 在项目运行中,我们需要对项目的出错或运行有了解,可以通过日志文件的查看来实现。因此,项目日志的打印就至关重要。本文给出一种logback日志的配置。改配置会在每天进行整理,同时区分不同的日志级别进行记录。
凡人飞
2020/09/21
2.3K0
SpringBoot——配置logback日志
SpringBoot MDC全局链路解决方案
在访问量较大的分布式系统中,时时刻刻在打印着巨量的日志,当我们需要排查问题时,需要从巨量的日志信息中找到本次排查内容的日志是相对复杂的,那么,如何才能使日志看起来逻辑清晰呢?如果每一次请求都有一个全局唯一的id,当我们需要排查时,根据其他日志打印关键字定位到对应请求的全局唯一id,再根据id去搜索、筛选即可找到对应请求全流程的日志信息。接下来就是需要找一种方案,可以生成全局唯一id和在不同的线程中存储这个id。
关忆北.
2023/10/11
9810
SpringBoot MDC全局链路解决方案
Spring Boot 日志记录(log)
Spring Boot 使用 Commons Logging 记录所有内部日志,但开放日志的底层实现。其为 Java Util Logging 、Log4J2 和 Logback 提供了默认配置。在每种情况下,日志记录器都预先配置为使用控制台输出,并且还提供可选的文件输出。
acc8226
2022/05/17
6230
Spring Boot 日志记录(log)
Docker安装ELK并实现JSON格式日志分析
ELK是elastic公司提供的一套完整的日志收集以及前端展示的解决方案,是三个产品的首字母缩写,分别是ElasticSearch、Logstash和Kibana。
我的小熊不见了丶
2019/10/25
1.4K0
Docker安装ELK并实现JSON格式日志分析
相关推荐
Spring Boot入门系列(十三)统一日志处理!
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验