相关文章推荐
英俊的大熊猫  ·  Spring ...·  1 年前    · 
独立的胡萝卜  ·  c# - Why is the ...·  1 年前    · 
rollingPolicy triggeringPolicy filter 。这些基本在项目中都很常用的。接下来我们看一下其他的功能点。包括日志的MDC做日志跟踪以及将日志添加自定义颜色,酷炫的显示效果。另外再大概说一下 pattern 中的占位符含义。

MDC实现日志跟踪

MDC在做日志跟踪的时候用的比较多。一个系统提供服务,提供给其他系统来调用,当其他系统调用的时候,入参带上一个唯一的请求标识(requestId),把这个requestId输出到日志中,这样两个系统直接就会形成一个执行链,用requestId串联起来,当出现错误时,可以在调用方查询对应的请求日志,也可以在服务方查询请求日志。定位问题很方便。输出日志的地方很多,不能每次输出都去get拿取requestId,拼接到日志中,很麻烦,也很容易遗漏。这个时候使用MDC配合logback中的 pattern 就很简单啦。

**实现思路:**首先请求过来,将requestId放到MDC中,然后在 pattern 中用表达式从MDC中获取到对应的requestId。

了解MDC

在MDC中提供了静态方法put,如同Map的put方法,进入看源码:

static MDCAdapter mdcAdapter;
public static void put(String key, String val) throws IllegalArgumentException {
    if (key == null) {
        throw new IllegalArgumentException("key parameter cannot be null");
    } else if (mdcAdapter == null) {
        throw new IllegalStateException("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA");
    } else {
        mdcAdapter.put(key, val); //调用成员变量mdcAdapter将键值对存储起来

然后就是进入到MDCAdapter类中找对应的put方法(MDCAdapter是一个接口,找到实现类LogbackMDCAdapter):

final ThreadLocal<Map<String, String>> copyOnThreadLocal = new ThreadLocal();//ThreadLocal
public void put(String key, String val) throws IllegalArgumentException {
    if (key == null) {
        throw new IllegalArgumentException("key cannot be null");
    } else {
        Map<String, String> oldMap = (Map)this.copyOnThreadLocal.get();//先从ThreadLocal取Map
        Integer lastOp = this.getAndSetLastOperation(1);
        if (!this.wasLastOpReadOrNull(lastOp) && oldMap != null) {
            oldMap.put(key, val);//Map存在直接存储
        } else {
            //Map不存在,先创建,再存储
            Map<String, String> newMap = this.duplicateAndInsertNewMap(oldMap);
            newMap.put(key, val);

源码很简单,就是通过ThreadLocal来维护一个线程共享的Map,然后将键值对放到Map里面。

MDC存值的内部逻辑已经了解,接下来怎么存进去就不是很难了。可以在请求进入的每个方法的第一行,将请求的requestId放到MDC中,但是这样就有点蠢。切面用一下,很简单。下面是实现代码:

* @Author: Joker * @Date: 2018/12/16 * @Desc: requestId不放在请求的参数中,放在一个统一的位置:请求头 @Component @Slf4j @Aspect public class RequestIdAspectJHandler { private static final String REQUEST_ID = "requestId"; @Pointcut("execution(* com.pingan.haofang.iot.*..*Controller.*(..))") public void pointcut() { @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); MDC.put(REQUEST_ID,request.getHeader(REQUEST_ID));//将requestId设置到MDC中 return joinPoint.proceed();

这里使用最简单的写法。代码就不多做解释。

在logback配置文件中利用pattern获取requestId

只是表达式写一下就可以了,也是非常简单的下面直接给示例:

<!-- %X{requestId:-defaultrequestId},':-'表示设置默认值,
当获取requestId为空的时候使用defaultrequestId替代,如果不需要默认值直接写成: %X{requestId}-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <pattern>[requestId:%X{requestId:-defaultrequestId}] %d %red([%thread]) %5level - %msg%n
    </pattern>
</encoder>

输出的日志格式如下:

[requestId:123] 2018-12-16 12:12:12.123 [main] INFO - this is log info

自定义颜色

在输出不同级别日志的时候,使用不同颜色来做标记,可以让输出的内容可识别性更高。这里就说一种自定义颜色的方式。

自定义颜色处理类

自定义颜色处理类需要继承ForegroundCompositeConverterBase,并指定泛型为ILoggingEvent,泛型类对象会作为getForegroundColorCode方法的默认参数,这里需要使用iLoggingEvent获取一些日志的内部属性。

* @Author: Joker * @Date: 2018/12/13 * @Desc: public class CustomLogColor extends ForegroundCompositeConverterBase<ILoggingEvent> { @Override protected String getForegroundColorCode(ILoggingEvent iLoggingEvent) { Level level = iLoggingEvent.getLevel(); switch (level.toInt()) { case Level.INFO_INT: return ANSIConstants.GREEN_FG; //INFO级别为绿色 case Level.WARN_INT: return ANSIConstants.YELLOW_FG;//WARN级别为黄色 default: return ANSIConstants.DEFAULT_FG;//默认颜色
logback.xml文件配置

配置很简单,直接定义颜色处理类,然后在pattern中使用即可。代码如下:

<!--自定义颜色处理类名称是:custom-->
<conversionRule conversionWord="custom" converterClass="com.itcrud.logback.demo.color.CustomLogColor"/>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <!--  %custom(%5level),用小括号来界定颜色作用的范围,%custom指定使用的处理类 -->
    <pattern>%blue([requestId:%X{requestId}]) %d %red([%thread]) %custom(%5level) - %msg%n
    </pattern>
</encoder>

当然这里除了颜色自定义,也可以使用logback内置的颜色,上面的pattern中有体现,在输出requestId和thread信息的时候分别使用到了%blue%red。具体提供了多少中颜色,可以去研究研究,这里不做赘述。

pattern的使用

在上面的两个功能点都反复的说到了pattern,说明它很重要也很基础。输出的日志就靠它来帮忙实现各种格式的排版。关于pattern的内容挺多的,这里不多说,如果想研究复杂的,可以到百度上找,相信会有很多。另外文末提供的参考文档中也是有详细的说明,可以作为对照的参考。(logback官方中文版文档的6.2.2节)

logger标签

最后加一个logger标签的说明,以前在项目中没看到有用过,这次在公司新开的项目中有体现,拿出来说一下。

logback.xml格式如下:

<logger name="com.itcrud.logback.UserService" level="info"/>

UserService格式如下:

public class UserService {
    private Logger log = LoggerFactory.getLogger("com.itcrud.logback.UserService");
    public String getUserInfo(Integer id){
        //业务代码
        log.info("请求成功!");
        return "";

UserService代码中获取日志对象Logger,这个时候没有设置日志的级别,那就是默认继承root上指定的日志级别。如果这个时候不想去继承root指定的日志级别,就只能自己去指定。就是使用logger标签,在logback.xml配置文件中指定需要使用的日志级别。(这里单看着可能有点懵,因为涉及到日志父级和继承关系,可以先看一下logback官方中文文档的第一章)

很久以前在开发中经常会用到这种方式创建Logger对象,但是现在基本都是注解式开发很简单。使用lombok,然后在类上加上@Slf4j的注解,就大功告成了。至于日志级别,都是直接继承root指定的。有时候用到一些老的框架有可能还真的需要用到logger标签,这也是没有办法的。作为一个了解,知道logger什么时候用,做什么用的即可。

上一篇关于logback的文章说明了logback的主要组成部分,其中包括appender、encoder、rollingPolicy、triggeringPolicy和filter。这些基本在项目中都很常...... 由于我不再使用 LogDNA,抱歉,我不能抽出时间来维护这个库。 欢迎您运行自己的 fork,但是还有另一个类似的库正在维护中。 我没用过。 如果其他人想采用这个库,请不要犹豫询问。 结束通知。 用于 Logback 的 LogDNA Appender LogDNA 是托管日志记录平台: ://logdna.com 这个小型库为 (一种流行的 JVM 日志子系统)提供了一个 appender。 appender 通过 HTTPS 将日志条目推送到 LogDNA Logback 的线程绑定存储 MDC 作为元数据发送到 LogDNA,以进行索引和搜索。 (见截图,以及更多下文) Logback 在已知位置使用 XML 文件,最常见的是classpath:/logback.xml 这是 logback.xml 的样子: <?xml version="1.0" e 在传统系统中,如果能够提供日志输出,基本上已经能够满足需求的。但一旦将系统拆分成两套及以上的系统,再加上负载均衡等,调用链路就变得复杂起来。 特别是进一步向微服务方向演化,如果没有日志的合理规划、链路追踪,那么排查日志将变得异常困难。 比如系统A、B、C,调用链路为A -> B -> C,如果每套服务都是双活,则调用路径有2的三次方种可能性。如果系统更多,服务更多,调用链路则会成指数增长。 因此,无论是几个简单的内部服务调用,还是复杂的微服务系统,都需要通过一个机制来实现日志的链路追踪。让 收集器:日志收集器负责收集和分组数据。 例如,收集器将标记MDC(本地线程),以对1次调用中的所有日志语句进行分组。 使用者:日志记录使用者包含可在logback.xml中配置的附加程序的实现。 使用者会将数据转换为JSON,以便将其保存到Elasticsearch。 曝光:日志记录曝光是一个HTML扩展轻松地将保存在Elasticsearch记录。 公开程序从ES隐藏数据,并根据数据提供便捷的JSON API和HTML可视化。 安装指南(进行中) 包括Jars Jars提供了登录时的扩展,并使用slf4j进行日志记录。 be.vrt.services.logging日志收集器$ {be.vrt.services.logging-version} be
IDEA 导入 logs-examples 1. log4j 的XML配置使用 2. log4j2 的配置详解,JDBC 配置,CloseableThreadContext 的使用(自定义输出日志文件 例如 logback MDC) 3.logback 的XML配置与使用,MDC的使用,SiftingAppender,DBAppender(c3p0,druid) 详细查看代码:README.md 文件 和 注释说明
MDCThreadExecutor extends ThreadPoolTaskExecutor 主要针对spring-context中的ThreadPoolTaskExecutor线程池进行了扩展,但也没做多少扩展,仅仅是引入了两个属性,如下: 1privateMap<String,String.. MDC(Mapped Diagnostic Context,映射调试上下文)是日志系统提供的一种方便在多线程条件下记录日志的功能 有什么用? 一个常用的场景就是Web服务器中给每个请求都给一个独特的请求id,在合理配置日志的layout之后,所有的日志都会打印这个请求id,这样一个请求下的所有日志信息都可以很方便的找到。 一个简单的理解可以认为是全局的marker信息,调用的时候不用类似... * Put a context value (the val parameter) as identified with the * key parameter into the current thread's context map. Note that * contrary to log4j, the val parameter can be nu
目录 ..........................................................................................................................I 译者声明.......................................................................................................................... 1 发布记录.......................................................................................................................... 1 1. 介绍.......................................................................................................................... 2 1.1. 什么是 logback ............................................................................................ 2 1.2. 第一步 ........................................................................................................ 2 1.2.1. 必要条件.............................................................................................. 2 1.3. 构建 logback................................................................................................ 5 2. 体系结构................................................................................................................... 6 2.1. logback 的体系结构 ..................................................................................... 6 2.2. Logger、Appender 和 Layout ........................................................................ 6 2.2.1. Logger 上下文 ...................................................................................... 6 2.2.2. 有效级别(Level)即级别继承 ............................................................. 7 2.2.3. 打印方法和基本选择规则 ..................................................................... 9 2.2.4. 获取 Logger........................................................................................ 10 2.2.5. Appender 和 Layout..............................................................................11 2.2.6. 参数化记录 ........................................................................................ 13 2.2.7. 更好的替代方法 ................................................................
slf4j-logback-mdc-玩具 tldr; 您的日志应为JSON。 不要使用Splunk解析日志行。 使用SLF4J,LogbackMDC的示例应用程序。 这是一个玩具。 ./gradlew run
Vue的材料组件 vue-mdc-adapter是一个集成的随后由谷歌推荐的最佳实践: 该项目旨在在坚持使用Vue精神(可接近,多功能和高性能)的同时,在易用性和自定义之间找到适当的平衡。 分叉参考codepen模板或vue-mdc-adapter codepen集合之一或CodeSandbox <!-- import reset material icons, fonts and vue-mdc-adapter stylesheets --> rel =" stylesheet "
MDC(Mapped Diagnostic Context,映射调试上下文)是日志系统提供的一种方便在多线程条件下记录日志的功能一个常用的场景就是Web服务器中给每个请求都分配一个独特的请求id,所有的日志都会打印这个请求id,这样一个请求下的所有日志信息都可以很方便的找到。 MDCAdapter其实就是做一些简单的kv操作整体结构 TtlMDCAdapter 重构{@link LogbackMDCAdapter}类,搭配TransmittableThreadLocal实现父子线程之间的数据传递建包org
今天把red5 rc1版本安装在服务器上,发现有错误,需要删除两个jar文件。 异常java.lang.ClassCastException:org.slf4j.helpers.BasicMDCAdapter不能转换为ch.qos.logback.classic.util.LogbackMDCAdapter java.lang.ClassCastException: org.s...