以前写过将应用程序或服务程序产生的日志直接写入搜索引擎的博客 其中基本过程就是 app->redis->logstash->elasticsearch 整个链路过程 原本想将redis替换成kafka的 无奈公司领导不让(不要问我为何没有缘由不想回答,哦也!就这么酷!!!)nginx
而后又写了相关的优化,其实道理很简单 就是 部署多个redis 多个logstash就ok了 (注意redis建议不要部署集群单节点就OK由于他只承担了消息传输的功能别无其余,架集群的好处就是APP应用本身分发负载了,若是是多个redis单节点须要个相似nginx的东西作负载转发,其实最好使用F5这类的硬件会更好)好了很少说废话下面直奔主题。git
遇到的问题github
一、去ES(ElasticSearch 如下简称ES)查询日志用关键字搜索要搜索好几回才能定位的问题?redis
二、多线程调用公用的方法不少时候是否是有点迷糊找不着北等等 不止这些spring
想要达到的目的数据库
经过关键字(关键字能够是订单号,操做码等能够标识一条信息,通常在数据库里面都是主键)一次查询出来全部的整个链路的相关日志多线程
好,咱们的目的很明确,不想各类过滤条件一大堆去定位真正想要的日志,一个关键搞定多全部。app
说道这里可能有不少童鞋对日志框架比较了解第一就会想到MDC,没错就是他。下面才是真正的主题,哈哈!框架
MDC我就很少介绍这里我在网上随便找了一个介绍的 若是熟悉能够略过(https://blog.csdn.net/liubo2012/article/details/46337063)elasticsearch
MDC其实就是在方法里面先后标记一下,而后在这个标记范围内(包括中间调用的方法嵌套)全部的日志都会打上相应的标签记录方便查询
那怎么和咱们以前的 方案结合和 咱们以前用的是下面这个包,这个包是支持MDC传输的具体源码你们能够参看github实现https://github.com/kmtong/logback-redis-appender
<dependency> <groupId>com.cwbase</groupId> <artifactId>logback-redis-appender</artifactId> <version>1.1.5</version> </dependency>
当咱们引入这个包以后logback.xml文件是以下配置的
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false" scan="true" scanPeriod="1 seconds"> <include resource="org/springframework/boot/logging/logback/base.xml" /> <!-- <jmxConfigurator/> --> <contextName>logback</contextName> <property name="log.path" value="\logs\logback.log" /> <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} -%5p ${PID} --- traceId:[%X{mdc_trace_id}] [%15.15t] %-40.40logger{39} : %m%n" /> <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}</file> <encoder> <pattern>${log.pattern}</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>info-%d{yyyy-MM-dd}-%i.log </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>10</maxHistory> </rollingPolicy> </appender> <appender name="redis" class="com.cwbase.logback.RedisAppender"> <tags>test</tags> <host>10.10.12.21</host> <port>6379</port> <key>spp</key> <mdc>true</mdc> <callerStackIndex>0</callerStackIndex> <location>true</location> <!-- <additionalField> <key>traceId</key> <value>@{destination}</value> </additionalField> --> </appender> <root level="info"> <!-- <appender-ref ref="file" /> --> <!-- <appender-ref ref="UdpSocket" /> --> <!-- <appender-ref ref="TcpSocket" /> --> <appender-ref ref="redis" /> </root> <!-- <logger name="com.example.logback" level="warn" /> --> </configuration>
咱们把<mdc>true</mdc>标签设置为true 默认是false就能够了,下面咱们看下咱们的测试代码
package com.zjs.canal.client.client; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; public class testaa { protected final static Logger logger = LoggerFactory.getLogger(testaa.class); @Test public void test(){ MDC.put("destination", "123456789"); for (int i = 0; i < 10; i++) { logger.info("aaaaaaaa"+i); test1(); } MDC.remove("destination"); } public void test1() { for (int i = 0; i < 10; i++) { logger.info("bbbbbbbb"+i); } } }
上面的测试有两层嵌套下面是ES日志输出
你们能够看到日志输出内容包含了两个方法,都包含相应的properties.destination字段而且值也是同样的(固然真正使用的时候destination MDC的关键字是动态的,选查询的主要关键字)
这样经过关键字一下就能把全部相关的日志都查询出来就能看出数据整个处理流程,这样就很是方便咱们的查询定位排查问题
我上面的代码有一段注释不知道你们有没有注意到
就是下面这段
<!-- <additionalField> <key>traceId</key> <value>@{destination}</value> </additionalField> -->
其实咱们把<mdc>true</mdc>这句设为false也是能够了不过须要添加一个字段来引用数据(把上面的配置取消注释)这样咱们就能够自定义命名跟踪字段的名称了(本人更倾向使用这种)
而后配置就办成下面这样
<appender name="redis" class="com.cwbase.logback.RedisAppender"> <tags>test</tags> <host>10.10.12.21</host> <port>6379</port> <key>spp</key> <!-- <mdc>true</mdc> --> <callerStackIndex>0</callerStackIndex> <location>true</location> <additionalField> <key>traceId</key> <value>@{destination}</value> </additionalField> </appender>
而后看下效果
这是以前的默认字段就没有值了mdc引用的值变成咱们新的字段里面去了
其实均可以开启 可是会打印两份MDC和自定义字段,这样就会重复了,因此说不必了
好了 今天就说的这里但愿对看博客的你有所帮助