SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過程
日志收集折騰過程
ELK
之前整合過ELK做日志采集,就是Elasticsearch + Logstash + Kibana:
- Elasticsearch:存儲引擎,存放日志內(nèi)容,利于全文檢索
- Logstash:數(shù)據(jù)傳輸管道,將日志內(nèi)容傳輸?shù)紼lasticsearch,并且支持過濾內(nèi)容,將內(nèi)容格式化后再傳輸,可以滿足絕大部分的應(yīng)用場景
- Kibana:開源的分析和可視化平臺,在這里查看Elasticsearch中的數(shù)據(jù)
對我來說ELK有點(diǎn)重,服務(wù)占用資源高,并且部署和維護(hù)有些復(fù)雜,我的個人服務(wù)器玩這個有點(diǎn)力不從心,所以一直有在尋找替代方案。
EFK
Elasticsearch + Filebeat + Kibana,用Filebeat替代Logstash做日志的收集,它是由Golang開發(fā),夠輕量,占用資源少,如果沒有過濾日志內(nèi)容進(jìn)行格式化的需求,用這個替代Logstash是很不錯的選擇。
ELFK
四個框架全用,網(wǎng)上看到有大佬這樣用,應(yīng)該是企業(yè)級別的部署,看著我就敬而遠(yuǎn)之,不敢玩。
自己擼一個
我對EFK的服務(wù)占用感到不滿,于是自己用Golang寫了一個輕量級工具,沒有做采集、過濾,僅僅是從日志文件夾中g(shù)rep出想要的內(nèi)容,其實(shí)和手動grep沒區(qū)別,不過可以用接口的方式查出想要的內(nèi)容,而且極其輕量,這個工具我還用過好一段時間。
我把EFK的搭建過程和手?jǐn)]工具的過程寫在了這里,感興趣可以去看看。
Graylog
最近我在折騰另一個日志收集方案,并且感覺不錯,就是Graylog,它需要整合Mongo + Elasticsearch,它比較簡單易用,提供網(wǎng)頁端可視化頁面,相當(dāng)于Kibana,還支持日志報警。
值得說明的是,它支持處理多行日志,而在ELK中,多行日志需要用Logstash做一些格式化配置,這一點(diǎn)來說Graylog就做的很棒。
至于為什么需要整合Mongo,是因?yàn)樾枰柚鶰ongo來保存一些Graylog的配置信息。
環(huán)境搭建
我喜歡用Docker來搭建環(huán)境,所以如果你通過其他方式,可以到官網(wǎng)尋求答案
首先拉取一下鏡像:
docker pull elasticsearch:7.12.0 docker pull graylog/graylog:4.3.6 docker pull mongo:4.2
docker-compose.yml:
version: '3'
services:
mongo:
image: mongo:4.2
container_name: mongo # graylog內(nèi)默認(rèn)連接名為mongo,所以這個不建議改
restart: always
volumes:
- /home/mycontainers/mongo/data:/data/db # 路徑映射
ports:
- 27017:27017
network_mode: mynetwork # 設(shè)置網(wǎng)段
elasticsearch:
image: elasticsearch:7.12.0
container_name: elasticsearch # graylog內(nèi)默認(rèn)連接名為elasticsearch,所以不建議改
environment:
- "TAKE_FILE_OWNERSHIP=true" # 掛載目錄需要這個,不然沒有權(quán)限
- "discovery.type=single-node" # 設(shè)置為單節(jié)點(diǎn),集群就等進(jìn)階再說了
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # 分配堆大小
volumes:
- /home/mycontainers/es/data:/usr/share/elasticsearch/data
- /home/mycontainers/es/logs:/usr/share/elasticsearch/logs
ulimits: # 調(diào)整 ulimits 以及 nprocedit
memlock:
soft: -1
hard: -1
deploy:
resources:
limits:
memory: 1g # 限制使用內(nèi)存
ports:
- 9200:9200
- 9300:9300
network_mode: mynetwork
graylog:
image: graylog/graylog:4.3.6
container_name: graylog
environment:
# echo -n "Enter Password: " && head -1 < /dev/stdin | tr -d '\n' | sha256sum | cut -d " " -f1
- GRAYLOG_PASSWORD_SECRET=somepasswordpepper # 用于密碼加密加鹽
- GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 # 密碼,默認(rèn)是admin,可以用上面的echo命令生成自己的密碼
- GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9009/ # 對外開放的鏈接,注意端口,我改成了9009
# volumes:
# - /home/mycontainers/graylog/config/graylog.conf:/usr/share/graylog/data/config/graylog.conf
network_mode: mynetwork
restart: always
depends_on:
- mongo # 依賴于mongo和es兩個環(huán)境
- elasticsearch
ports:
- 9009:9000 # 端口映射
# Syslog TCP
- 1514:1514
# Syslog UDP
- 1514:1514/udp
# GELF TCP
- 12201:12201
# GELF UDP
- 12201:12201/udp
執(zhí)行運(yùn)行命令:
docker-compose -f docker-compose.yml up
但有時候,我們在之前就已經(jīng)部署好了Mongo和ES環(huán)境,所以不會在一個docker-compose文件中配置三個環(huán)境,我們把內(nèi)容拆開如下:
es.yml:
version: '3'
services:
elasticsearch:
image: elasticsearch:7.12.0
container_name: elasticsearch # graylog內(nèi)默認(rèn)連接名為elasticsearch,所以不建議改
environment:
- "TAKE_FILE_OWNERSHIP=true"
- "discovery.type=single-node"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
volumes:
- /etc/localtime:/etc/localtime
- /home/mycontainers/es/data:/usr/share/elasticsearch/data
- /home/mycontainers/es/logs:/usr/share/elasticsearch/logs
ulimits: # 調(diào)整 ulimits 以及 nprocedit
memlock:
soft: -1
hard: -1
deploy:
resources:
limits:
memory: 1g # 限制使用內(nèi)存
ports:
- 9200:9200
- 9300:9300
network_mode: mynetwork
mongo.yml:
version: '3'
services:
mongo:
image: mongo:4.2
container_name: mongo # graylog內(nèi)默認(rèn)連接名為mongo,所以這個不建議改
restart: always
volumes:
- /etc/localtime:/etc/localtime
- /home/mycontainers/mongo/data:/data/db
ports:
- 27017:27017
network_mode: mynetwork
graylog.yml:
version: '3'
services:
graylog:
image: graylog/graylog:4.3.6
container_name: graylog
environment:
# echo -n "Enter Password: " && head -1 < /dev/stdin | tr -d '\n' | sha256sum | cut -d " " -f1
- GRAYLOG_PASSWORD_SECRET=somepasswordpepper
- GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
- GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9009/
- GARYLOG_ELASTICSEARCH_HOSTS=http://elasticsearch:9200 # 鏈接es,這里是容器間通訊,所以寫容器名
- GRAYLOG_MONGODB_URI=mongodb://mongo:27017/graylog # 同上
volumes:
- /home/mycontainers/graylog/config/graylog.conf:/usr/share/graylog/data/config/graylog.conf # 指定配置文件,用于修改時區(qū)
network_mode: mynetwork
restart: always
ports:
- 9009:9000
# Syslog TCP
- 1514:1514
# Syslog UDP
- 1514:1514/udp
# GELF TCP
- 12201:12201
# GELF UDP
- 12201:12201/udp
不同點(diǎn)在于手動配置mongo和es,還有多了一個配置文件映射,因?yàn)間raylog默認(rèn)UTC時區(qū),我們的日志文件會相差8小時,所以在第一次啟動成功graylog后,我們把它的配置文件拷貝出來,修改里面的root_timezone參數(shù),再映射回去即可。
創(chuàng)建輸入
現(xiàn)在我們可以訪問Graylog了:http://xxx:9009
來創(chuàng)建一個輸入:



>
勾選Global,Title隨便寫一個,其他不用改,保存即可,就能得到:

回到Search標(biāo)簽頁,等日志文件輸入即可。
Spring Boot整合Graylog
Maven依賴:
<!--graylog日志依賴-->
<dependency>
<groupId>de.siegmar</groupId>
<artifactId>logback-gelf</artifactId>
<version>3.0.0</version>
</dependency>
然后是logback的配置,這個根據(jù)需要使用就好,在resource中:
logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--解決在項(xiàng)目目錄中生成LOG_PATH_IS_UNDEFINED文件-->
<property name="LOG_PATH" value="${LOG_PATH:-${java.io.tmpdir:-/logs}}"/>
<!-- 引入SpringBoot的默認(rèn)配置文件defaults.xml -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!-- 引入SpringBoot中內(nèi)置的控制臺輸出配置文件console-appender.xml -->
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<!-- 引入自定義的文件輸出配置文件logback-spring-file-level.xml -->
<include resource="logback-spring-file-level.xml"/>
<!-- 設(shè)置root logger的級別為INFO,并將控制臺輸出和文件輸出中的appender都添加到root logger下 -->
<root level="INFO">
<!--沒有這行,控制臺將不會有輸出,完全由日志進(jìn)行輸出-->
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
<appender-ref ref="GELF"/>
</root>
<!-- jmx可以動態(tài)管理logback配置-->
<jmxConfigurator/>
</configuration>
logback-spring-file-level.xml:
<?xml version="1.0" encoding="UTF-8"?>
<included>
<!-- 從配置文件中讀取-->
<springProperty scope="context" name="APP_NAME" source="graylog.appName"/>
<springProperty scope="context" name="GRAYLOG_HOST" source="graylog.host"/>
<springProperty scope="context" name="GRAYLOG_PORT" source="graylog.port"/>
<!--INFO Level的日志-->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- %i用來標(biāo)記分割日志的序號 -->
<fileNamePattern>${LOG_PATH}.INFO.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
<!-- 經(jīng)過試驗(yàn),maxHistory是指指定天數(shù)內(nèi),而不是多少天-->
<maxFileSize>50MB</maxFileSize>
<maxHistory>15</maxHistory>
<totalSizeCap>50MB</totalSizeCap>
</rollingPolicy>
<!-- 配置日志的級別過濾器,只保留INFO Level的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 格式化輸出-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level -[%X{traceId}] - %msg%n</pattern>
</encoder>
</appender>
<!--WARN Level的日志-->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- %i用來標(biāo)記分割日志的序號 -->
<fileNamePattern>${LOG_PATH}.WARN.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>15</maxHistory>
<totalSizeCap>50MB</totalSizeCap>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--過濾級別-->
<level>WARN</level>
<!--onMatch:符合過濾級別的日志。ACCEPT:立即處理-->
<onMatch>ACCEPT</onMatch>
<!--onMismatch:不符合過濾級別的日志。DENY:立即拋棄-->
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level -[%X{traceId}] - %msg%n</pattern>
</encoder>
</appender>
<!--ERROR Level的日志-->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- %i用來標(biāo)記分割日志的序號 -->
<fileNamePattern>${LOG_PATH}.ERROR.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>15</maxHistory>
<totalSizeCap>50MB</totalSizeCap>
<!--<cleanHistoryOnStart>true</cleanHistoryOnStart>-->
</rollingPolicy>
<!--對指定級別的日志進(jìn)行過濾-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--過濾級別-->
<level>ERROR</level>
<!--onMatch:符合過濾級別的日志。ACCEPT:立即處理-->
<onMatch>ACCEPT</onMatch>
<!--onMismatch:不符合過濾級別的日志。DENY:立即拋棄-->
<onMismatch>DENY</onMismatch>
</filter>
<!--日志輸出格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level - [%X{traceId}] - %msg%n</pattern>
</encoder>
</appender>
<!--自定義日志-->
<appender name="CUSTOM_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- %i用來標(biāo)記分割日志的序號 -->
<fileNamePattern>${LOG_PATH}.MYLOGGER.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
<!-- 經(jīng)過試驗(yàn),maxHistory是指指定天數(shù)內(nèi),而不是多少天-->
<maxFileSize>300MB</maxFileSize>
<maxHistory>15</maxHistory>
<totalSizeCap>300MB</totalSizeCap>
</rollingPolicy>
<!-- 配置日志的級別過濾器,只保留INFO Level的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 格式化輸出-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"}\t%X{traceId}\t%msg%n</pattern>
</encoder>
</appender>
<!--自定義日志日志不用綁定在root下,只記錄指定輸出-->
<logger name="my_logger" additivity="false">
<appender-ref ref= "CUSTOM_FILE"/>
</logger>
<appender name="GELF" class="de.siegmar.logbackgelf.GelfUdpAppender">
<!--graylog服務(wù)地址-->
<graylogHost>${GRAYLOG_HOST}</graylogHost>
<!--連接端口-->
<graylogPort>${GRAYLOG_PORT}</graylogPort>
<encoder class="de.siegmar.logbackgelf.GelfEncoder">
<originHost>${APP_NAME:-demo}</originHost>
<!--發(fā)送日志級別名稱,默認(rèn)以數(shù)字代表日志級別-->
<includeLevelName>true</includeLevelName>
</encoder>
</appender>
</included>
我們在logback中引用了配置文件的系統(tǒng)變量,所以在application.yml中要添加這一段,當(dāng)然硬寫進(jìn)xml也可以:
application.yml
logging:
file:
path: _mylogs/${server.port}.logs # 日志保存路徑
graylog:
host: mylocalhost # graylog服務(wù)host
port: 12201 # graylog服務(wù)端口
appName: graylogDemo # 應(yīng)用名,可填
啟動Spring應(yīng)用,打印幾條日志:
@RestController
public class TestController {
private static final Logger log = LoggerFactory.getLogger(TestController.class);
@GetMapping("/i")
public void info() {
log.info("info...................");
}
@GetMapping("/w")
public void warn() {
log.warn("warn...................");
}
@GetMapping("/e")
public void error() {
// log.error("error...................");
int i = 1/0;
// LogUtil.error("自定義異常");
}
}
稍等片刻,順利的話我們就能在Graylog中查看到剛剛輸出的日志了,至此大功告成。

總結(jié)
本篇文章只是說明了Graylog的一個入門使用,進(jìn)階的玩法可能要后面才有時間整理了。
不管用什么方案做日志收集,我認(rèn)為只要簡單易用,穩(wěn)定靠譜就好,ELK作為當(dāng)前主流的日志收集框架,除了部署麻煩些,耗費(fèi)資源高些之外并沒有明顯短板,所以ELK也好,Graylog也罷,只要適合自己就可以。
以上就是SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過程的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Graylog日志收集的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java Class文件結(jié)構(gòu)解析常量池字節(jié)碼
這篇文章主要為大家介紹了java Class文件的整體結(jié)構(gòu)解析常量池字節(jié)碼詳細(xì)講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
Java mutable對象和immutable對象的區(qū)別說明
這篇文章主要介紹了Java mutable對象和immutable對象的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
springboot+vue實(shí)現(xiàn)Token自動續(xù)期(雙Token方案)
雙Token方案通過訪問令牌和刷新令牌提高用戶登錄安全性和體驗(yàn),訪問令牌有效期短,包含用戶信息,用于請求校驗(yàn),本文就來介紹一下springboot+vue實(shí)現(xiàn)Token自動續(xù)期(雙Token方案),感興趣的可以了解一下2024-10-10
logback StatusListener的定義方法源碼解讀
這篇文章主要為大家介紹了logback StatusListener的定義方法源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
java遍歷http請求request的所有參數(shù)實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猨ava遍歷http請求request的所有參數(shù)實(shí)現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09
SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄功能(多 Realm 認(rèn)證)
這篇文章主要介紹了SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄(多 Realm 認(rèn)證),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02

