之前寫過将應用程式或服務程式産生的日志直接寫入搜尋引擎的部落格 其中基本過程就是 app->redis->logstash->elasticsearch 整個鍊路過程 本來想将redis替換成kafka的 無奈公司上司不讓(不要問我為什麼沒有原因不想回答,哦也!就這麼酷!!!)
然後又寫了相關的優化,其實道理很簡單 就是 部署多個redis 多個logstash就ok了 (注意redis建議不要部署叢集單節點就OK因為他隻承擔了消息傳輸的功能别無其他,架叢集的好處就是APP應用自己分發負載了,如果是多個redis單節點需要個類似nginx的東西做負載轉發,其實最好使用F5這類的硬體會更好)好了不多說廢話下面直奔主題。
遇到的問題
1、去ES(ElasticSearch 以下簡稱ES)查詢日志用關鍵字搜尋要搜尋好幾次才能定位的問題?
2、多線程調用公用的方法很多時候是不是有點迷糊找不着北等等 不止這些
想要達到的目的
通過關鍵字(關鍵字可以是訂單号,操作碼等可以辨別一條資訊,一般在資料庫裡面都是主鍵)一次查詢出來所有的整個鍊路的相關日志
好,我們的目的很明确,不想各種過濾條件一大堆去定位真正想要的日志,一個關鍵搞定多所有。
說道這裡可能有很多童鞋對日志架構比較了解第一就會想到MDC,沒錯就是他。下面才是真正的主題,哈哈!
MDC我就不多介紹這裡我在網上随便找了一個介紹的 如果熟悉可以略過(https://blog.csdn.net/liubo2012/article/details/46337063)
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和自定義字段,這樣就會重複了,是以說沒必要了
好了 今天就說的這裡希望對看部落格的你有所幫助