SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過(guò)程
日志收集折騰過(guò)程
ELK
之前整合過(guò)ELK做日志采集,就是Elasticsearch + Logstash + Kibana:
- Elasticsearch:存儲(chǔ)引擎,存放日志內(nèi)容,利于全文檢索
- Logstash:數(shù)據(jù)傳輸管道,將日志內(nèi)容傳輸?shù)紼lasticsearch,并且支持過(guò)濾內(nèi)容,將內(nèi)容格式化后再傳輸,可以滿足絕大部分的應(yīng)用場(chǎng)景
- Kibana:開源的分析和可視化平臺(tái),在這里查看Elasticsearch中的數(shù)據(jù)
對(duì)我來(lái)說(shuō)ELK有點(diǎn)重,服務(wù)占用資源高,并且部署和維護(hù)有些復(fù)雜,我的個(gè)人服務(wù)器玩這個(gè)有點(diǎn)力不從心,所以一直有在尋找替代方案。
EFK
Elasticsearch + Filebeat + Kibana,用Filebeat替代Logstash做日志的收集,它是由Golang開發(fā),夠輕量,占用資源少,如果沒有過(guò)濾日志內(nèi)容進(jìn)行格式化的需求,用這個(gè)替代Logstash是很不錯(cuò)的選擇。
ELFK
四個(gè)框架全用,網(wǎng)上看到有大佬這樣用,應(yīng)該是企業(yè)級(jí)別的部署,看著我就敬而遠(yuǎn)之,不敢玩。
自己擼一個(gè)
我對(duì)EFK的服務(wù)占用感到不滿,于是自己用Golang寫了一個(gè)輕量級(jí)工具,沒有做采集、過(guò)濾,僅僅是從日志文件夾中g(shù)rep出想要的內(nèi)容,其實(shí)和手動(dòng)grep沒區(qū)別,不過(guò)可以用接口的方式查出想要的內(nèi)容,而且極其輕量,這個(gè)工具我還用過(guò)好一段時(shí)間。
我把EFK的搭建過(guò)程和手?jǐn)]工具的過(guò)程寫在了這里,感興趣可以去看看。
Graylog
最近我在折騰另一個(gè)日志收集方案,并且感覺不錯(cuò),就是Graylog,它需要整合Mongo + Elasticsearch,它比較簡(jiǎn)單易用,提供網(wǎng)頁(yè)端可視化頁(yè)面,相當(dāng)于Kibana,還支持日志報(bào)警。
值得說(shuō)明的是,它支持處理多行日志,而在ELK中,多行日志需要用Logstash做一些格式化配置,這一點(diǎn)來(lái)說(shuō)Graylog就做的很棒。
至于為什么需要整合Mongo,是因?yàn)樾枰柚鶰ongo來(lái)保存一些Graylog的配置信息。
環(huán)境搭建
我喜歡用Docker來(lái)搭建環(huán)境,所以如果你通過(guò)其他方式,可以到官網(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,所以這個(gè)不建議改 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" # 掛載目錄需要這個(gè),不然沒有權(quán)限 - "discovery.type=single-node" # 設(shè)置為單節(jié)點(diǎn),集群就等進(jìn)階再說(shuō)了 - "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/ # 對(duì)外開放的鏈接,注意端口,我改成了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兩個(gè)環(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
但有時(shí)候,我們?cè)谥熬鸵呀?jīng)部署好了Mongo和ES環(huán)境,所以不會(huì)在一個(gè)docker-compose文件中配置三個(gè)環(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,所以這個(gè)不建議改 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 # 指定配置文件,用于修改時(shí)區(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)在于手動(dòng)配置mongo和es,還有多了一個(gè)配置文件映射,因?yàn)間raylog默認(rèn)UTC時(shí)區(qū),我們的日志文件會(huì)相差8小時(shí),所以在第一次啟動(dòng)成功graylog后,我們把它的配置文件拷貝出來(lái),修改里面的root_timezone參數(shù),再映射回去即可。
創(chuàng)建輸入
現(xiàn)在我們可以訪問(wèn)Graylog了:http://xxx:9009
來(lái)創(chuàng)建一個(gè)輸入:
>
勾選Global,Title隨便寫一個(gè),其他不用改,保存即可,就能得到:
回到Search標(biāo)簽頁(yè),等日志文件輸入即可。
Spring Boot整合Graylog
Maven依賴:
<!--graylog日志依賴--> <dependency> <groupId>de.siegmar</groupId> <artifactId>logback-gelf</artifactId> <version>3.0.0</version> </dependency>
然后是logback的配置,這個(gè)根據(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)置的控制臺(tá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的級(jí)別為INFO,并將控制臺(tái)輸出和文件輸出中的appender都添加到root logger下 --> <root level="INFO"> <!--沒有這行,控制臺(tái)將不會(huì)有輸出,完全由日志進(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可以動(dòng)態(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用來(lái)標(biāo)記分割日志的序號(hào) --> <fileNamePattern>${LOG_PATH}.INFO.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 單個(gè)日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB --> <!-- 經(jīng)過(guò)試驗(yàn),maxHistory是指指定天數(shù)內(nèi),而不是多少天--> <maxFileSize>50MB</maxFileSize> <maxHistory>15</maxHistory> <totalSizeCap>50MB</totalSizeCap> </rollingPolicy> <!-- 配置日志的級(jí)別過(guò)濾器,只保留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用來(lái)標(biāo)記分割日志的序號(hào) --> <fileNamePattern>${LOG_PATH}.WARN.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 單個(gè)日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB --> <maxFileSize>50MB</maxFileSize> <maxHistory>15</maxHistory> <totalSizeCap>50MB</totalSizeCap> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!--過(guò)濾級(jí)別--> <level>WARN</level> <!--onMatch:符合過(guò)濾級(jí)別的日志。ACCEPT:立即處理--> <onMatch>ACCEPT</onMatch> <!--onMismatch:不符合過(guò)濾級(jí)別的日志。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用來(lái)標(biāo)記分割日志的序號(hào) --> <fileNamePattern>${LOG_PATH}.ERROR.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 單個(gè)日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB --> <maxFileSize>50MB</maxFileSize> <maxHistory>15</maxHistory> <totalSizeCap>50MB</totalSizeCap> <!--<cleanHistoryOnStart>true</cleanHistoryOnStart>--> </rollingPolicy> <!--對(duì)指定級(jí)別的日志進(jìn)行過(guò)濾--> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!--過(guò)濾級(jí)別--> <level>ERROR</level> <!--onMatch:符合過(guò)濾級(jí)別的日志。ACCEPT:立即處理--> <onMatch>ACCEPT</onMatch> <!--onMismatch:不符合過(guò)濾級(jí)別的日志。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用來(lái)標(biāo)記分割日志的序號(hào) --> <fileNamePattern>${LOG_PATH}.MYLOGGER.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 單個(gè)日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB --> <!-- 經(jīng)過(guò)試驗(yàn),maxHistory是指指定天數(shù)內(nèi),而不是多少天--> <maxFileSize>300MB</maxFileSize> <maxHistory>15</maxHistory> <totalSizeCap>300MB</totalSizeCap> </rollingPolicy> <!-- 配置日志的級(jí)別過(guò)濾器,只保留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ā)送日志級(jí)別名稱,默認(rèn)以數(shù)字代表日志級(jí)別--> <includeLevelName>true</includeLevelName> </encoder> </appender> </included>
我們?cè)趌ogback中引用了配置文件的系統(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)用名,可填
啟動(dò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é)
本篇文章只是說(shuō)明了Graylog的一個(gè)入門使用,進(jìn)階的玩法可能要后面才有時(shí)間整理了。
不管用什么方案做日志收集,我認(rèn)為只要簡(jiǎn)單易用,穩(wěn)定靠譜就好,ELK作為當(dāng)前主流的日志收集框架,除了部署麻煩些,耗費(fèi)資源高些之外并沒有明顯短板,所以ELK也好,Graylog也罷,只要適合自己就可以。
以上就是SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過(guò)程的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Graylog日志收集的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決SpringMVC、tomcat、Intellij idea、ajax中文亂碼問(wèn)題
這篇文章主要介紹了解決SpringMVC、tomcat、Intellij idea、ajax中文亂碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09springboot2.x 接入阿里云市場(chǎng)短信發(fā)送的實(shí)現(xiàn)
本文主要介紹了springboot2.x 接入阿里云市場(chǎng)短信發(fā)送的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11利用Java實(shí)現(xiàn)word導(dǎo)入導(dǎo)出富文本(含圖片)的詳細(xì)代碼
這篇文章主要為大家詳細(xì)介紹了利用Java實(shí)現(xiàn)word導(dǎo)入導(dǎo)出富文本(含圖片),文中的示例代碼講解詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴可以學(xué)習(xí)一下2024-02-02JAVA中堆、棧,靜態(tài)方法和非靜態(tài)方法的速度問(wèn)題
這篇文章主要介紹了JAVA中堆、棧,靜態(tài)方法和非靜態(tài)方法的速度問(wèn)題,堆和棧得速度性能分析多角度給大家分析,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08Java如何利用CompletableFuture描述任務(wù)之間的關(guān)系
Java如何根據(jù)線程的執(zhí)行結(jié)果執(zhí)行下一步動(dòng)作呢,F(xiàn)uture的另一個(gè)實(shí)現(xiàn)類CompletableFuture能夠優(yōu)雅的解決異步化問(wèn)題,下面就跟隨小編一起了解一下吧2023-07-07Spring依賴注入的兩種方式(根據(jù)實(shí)例詳解)
這篇文章主要介紹了Spring依賴注入的兩種方式(根據(jù)實(shí)例詳解),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05