參考地址:https://www.cnblogs.com/zys2019/p/14816634.html
1. 概述
筆者在學習docker的相關知識,本著talk is cheap show me the code 原則,實際操作下,正好上面的博主分享了文件,我照著做成功了,只是有些細節上面的問題,需要解決下
2. ELK架構
- Elasticsearch是個開源分散式搜尋引擎,提供蒐集、分析、儲存資料三大功能。
- Logstash 主要是用來日誌的蒐集、分析、過濾日誌的工具,支援大量的資料獲取方式。
- Kibana 也是一個開源和免費的工具,Kibana可以為 Logstash 和 ElasticSearch 提供的日誌分析友好的 Web 介面,可以幫助彙總、分析和搜尋重要資料日誌。
2.1. 部署ELK
建立docker-elk目錄,在此目錄建立檔案和其他目錄
mkdir /opt/docker_elk
建立logstash配置檔案
mkdir /opt/docker_elk/logstash
touch /opt/docker_elk/logstash/logstash.conf
配置logstash.conf
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 4560
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "logstash-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
建立docker-compose.yml檔案 , touch /opt/docker_elk/docker-compose.yml
version: '3.7'
services:
elasticsearch:
image: elasticsearch:7.6.2
container_name: elasticsearch
privileged: true
user: root
environment:
#設定叢集名稱為elasticsearch
- cluster.name=elasticsearch
#以單一節點模式啟動
- discovery.type=single-node
#設定使用jvm記憶體大小
- ES_JAVA_OPTS=-Xms512m -Xmx512m
volumes:
- /opt/docker_elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins
- /opt/docker_elk/elasticsearch/data:/usr/share/elasticsearch/data
ports:
- 9200:9200
- 9300:9300
networks:
- elk-network
logstash:
image: logstash:7.6.2
container_name: logstash
ports:
- 4560:4560
privileged: true
environment:
- TZ=Asia/Shanghai
volumes:
#掛載logstash的配置檔案
- /opt/docker_elk/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
depends_on:
- elasticsearch
links:
#可以用es這個域名訪問elasticsearch服務
- elasticsearch:es
networks:
- elk-network
kibana:
image: kibana:7.6.2
container_name: kibana
ports:
- 5601:5601
privileged: true
links:
#可以用es這個域名訪問elasticsearch服務
- elasticsearch:es
depends_on:
- elasticsearch
environment:
#設定訪問elasticsearch的地址
- elasticsearch.hosts=http://es:9200
networks:
- elk-network
networks:
elk-network:
driver: bridge
進入docker_elk目錄 啟動docker-compose
#啟動
docker-compose up -d
#關閉
docker-compose down
#重啟某個容器
docker-compose restart logstash
2.2. kibana
輸入http://192.168.56.188:5601/,訪問Kibana web介面。點選左側設定,進入Management介面
點選index pattern,船艦logstash-*索引
2.3. log4j記錄日誌
要使用log4j2,則必須排除SpringBoot自帶的日誌。
- 排除logback並匯入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<!-- 引入log4j日誌時需去掉預設的logback -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 日誌管理log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
- 在資源目錄下新建log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日誌級別以及優先順序排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--
status="warn" Configuration後面日誌框架本身的輸出日誌級別,可以不加入
monitorInterval="5" 自動載入配置檔案的間隔時間, 不低於 5 秒
注: 我們的配置檔案修改後在生產環境下無需重啟應用, 可以實現熱更新的效果
-->
<Configuration monitorInterval="5">
<!--全域性屬性-->
<Properties>
<Property name="APP_NAME">coding</Property>
<Property name="LOG_FILE_PATH">/Users/A-Study/logs/${APP_NAME}</Property>
<Property name="PATTERN_FORMAT">%date{yyyy-MM-dd HH:mm:ss.SSS}$$%mdc{logId}$$%mdc{hostName}$$%mdc{ip}$$%level$$%mdc{module}$$%class$$%method$$%msg%n</Property>
</Properties>
<!--輸出源-->
<Appenders>
<!--輸出到控制檯-->
<Console name="Console" target="SYSTEM_OUT"><!--輸出的型別SYSTEM_ERR-->
<PatternLayout pattern="${PATTERN_FORMAT}"/>
</Console>
<!--輸出到logstash的appender-->
<Socket name="Socket" host="192.168.56.188" port="4560" protocol="TCP">
<!--輸出到logstash的日誌格式-->
<PatternLayout pattern="${PATTERN_FORMAT}"/>
</Socket>
<!--輸出info資訊日誌到檔案 用來定義超過指定大小自動刪除舊的建立新的的Appender.-->
<RollingFile name="RollingInfoFile" fileName="${LOG_FILE_PATH}/info.log"
filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/info-%d{yyyyMMdd}-%i.log.gz">
<!--控制檯只輸出level及以上級別的資訊(onMatch),其他的直接拒絕(onMismatch)-->
<Filters>
<ThresholdFilter level="warn" onMatch="DENY"
onMismatch="NEUTRAL"/> <!--高於warn級別就放行,低於這個級別就攔截-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<PatternLayout>
<pattern>${PATTERN_FORMAT}</pattern> <!--檔案路徑-->
</PatternLayout>
<!--設定檔案具體拆分規則-->
<Policies>
<!--在系統啟動時, 觸發拆分規則,生產一個新的日誌檔案-->
<OnStartupTriggeringPolicy/>
<!--按照檔案大小拆分, 30 MB -->
<SizeBasedTriggeringPolicy size="30 MB"/>
<!--按照時間節點拆分, 規則根據filePattern定義的-->
<TimeBasedTriggeringPolicy/>
</Policies>
<!--在同一個目錄下,檔案的個數限定為 30 個, 超過進行覆蓋-->
<DefaultRolloverStrategy max="30"/>
</RollingFile>
<!--輸出錯誤日誌到檔案-->
<RollingFile name="RollingErrorFile" fileName="${LOG_FILE_PATH}/error.log"
filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/error-%d{yyyyMMdd}-%i.log.gz">
<!--控制檯只輸出level及以上級別的資訊(onMatch),其他的直接拒絕(onMismatch)-->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout>
<pattern>${PATTERN_FORMAT}</pattern>
</PatternLayout>
<Policies>
<!--在系統啟動時, 觸發拆分規則,生產一個新的日誌檔案-->
<OnStartupTriggeringPolicy/>
<!--按照檔案大小拆分, 30 MB -->
<SizeBasedTriggeringPolicy size="30 MB"/>
<!--按照時間節點拆分, 規則根據filePattern定義的-->
<TimeBasedTriggeringPolicy/>
</Policies>
<!--在同一個目錄下,檔案的個數限定為 30 個, 超過進行覆蓋-->
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<!--定義logger,日誌記錄器配置-->
<Loggers>
<!--過濾掉spring和mybatis的一些無用的DEBUG資訊-->
<Logger name="org.springframework" level="INFO"/>
<Logger name="org.mybatis" level="INFO"/>
<!-- LOG "com.luis*" at TRACE level -->
<Logger name="com.luis" level="INFO"/>
<!--使用 rootLogger 配置 日誌級別 level="trace"-->
<Root level="INFO">
<!--指定日誌使用的處理器-->
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingInfoFile"/>
<AppenderRef ref="RollingErrorFile"/>
<AppenderRef ref="Async"/>
<AppenderRef ref="Socket"/>
</Root>
</Loggers>
</Configuration>
主要是Socket 那部分配置,筆者的mdc裡面的欄位有自定義,在專案日誌切面部分做了MDC輸入值的處理,非原始配置
日誌能夠上傳到es中,kibana裡面可以檢視到
2.4. logstash檔案資訊切割
對應logstash,預設是格式是使用的logback的預設格式,一旦使用log4j2或其他日誌框架來指定日誌的輸出格式時,那麼logstash便無法解析,需要進行自定義過濾。
2.4.1. 自定義過濾
筆者使用的是
<Property name="PATTERN_FORMAT">%date{yyyy-MM-dd HH:mm:ss.SSS}$$%mdc{logId}$$%mdc{hostName}$$%mdc{ip}$$%level$$%mdc{module}$$%class$$%method$$%msg%n</Property>
在logstash.conf中新增的filter過濾規則如下
filter {
grok {
match => {
"message" => "^%{TIMESTAMP_ISO8601:timestamp}\$\$(?<logId>[a-fA-F0-9]{32})?\$\$(?<hostName>[^\$]+)\$\$(?<ip>%{IP})\$\$%{WORD:level}\$\$(?<module>[^\$]*)?\$\$(?<class>.*?)\$\$(?<method>[^\\$]+)\$\$(?<msg>.*)"
}
}
date {
match => ["timestamp", "yyyy-MM-dd HH:mm:ss.SSS"]
target => "@timestamp"
}
mutate {
remove_field => ["message","port"]
}
}
顯示結果如下:
2.4.2. 多行問題
有時輸出的是異常日誌,存在多行問題,並不是按照這個格式列印,需要修改input配置,支援多行的日誌
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 4560
codec => multiline {
pattern => "^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}" # 確保這與您的日誌格式匹配
negate => true
what => "previous"
auto_flush_interval => 1
}
}
}
這樣列印出來的支援多行合併
2.4.3. 遺留問題
目前只是部署了ELK,而且還是單機模式,當前的日誌蒐集使用的是tcp,由於多行的日誌,蒐集不知道下一次什麼時候結束,所以當前的部署方式存在當前請求的介面日誌只列印了部分,下一次請求來了時,上一次的日誌才會完全列印出
解決這個問題,一個是自己部署虛擬機器的配置儘量高一點
再一個可以部署filebeat,來進行最佳化日誌收集過濾