文章目錄
- 前言
- 一、組件介紹
- (一)Loki
- 特點
- 架構
- 適用場景
- 總結
- (二)Loki4j
- 特點
- (三)Grafana
- 特點
- 適用場景
- 二、組件配置
- (一)Loki
- (二)Grafana
- 三、項目搭建
- 參考文章
前言
日志在任何一個Web應用中都是不可忽視的存在,它已經成為大部分系統的標準組成部分。搭建日志可視化的主要目的是為了更好地理解和管理應用程序產生的大量日志數據。日志數據對于了解系統的運行狀態、診斷問題以及優化性能至關重要。ELK日志可視化系統(Elasticsearch + Logstash + Kibana)太重太麻煩,安裝的東西很多,本文介紹一款新的 輕量級日志系統
,基本組成部分為:SpringBoot + Loki4j + Loki + Grafana,下面分別介紹Loki4j、Loki、Grafana這幾個組件,然后創建一個簡單的SpringBoot項目,來演示如何集成使用這幾個組件搭建一個輕量級的日志系統。
本文源碼倉庫地址:Gitee
一、組件介紹
(一)Loki
Loki 是一個開源的日志聚合系統,由 Grafana Labs 開發和維護。Loki 的設計目標是提供一種高效、可擴展的方式來收集、索引和查詢結構化日志數據
。Loki 專注于日志數據,與傳統的日志管理系統(如 ELK Stack)相比,它采用了不同的方法來處理日志數據。
特點
標簽查詢
:- Loki 使用類似于 Prometheus 的標簽查詢模型,允許用戶通過標簽來過濾和聚合日志數據。
- 這種模型非常適合大規模的日志數據查詢和分析。
無索引日志存儲
:- Loki 不對原始日志數據進行全文索引,而是將日志數據按流存儲,并使用標簽來標識每個流。
- 這種方法降低了存儲成本,并提高了查詢性能。
水平可擴展性
:- Loki 能夠水平擴展,通過增加更多的節點來處理更多的日志數據。
- 這使得 Loki 非常適合處理大規模的日志數據集。
高可用性
:- Loki 支持高可用性部署,可以配置多個實例來確保數據的持久性和服務的連續性。
多租戶支持
:- Loki 支持多租戶部署,不同的組織或團隊可以在同一套基礎設施上獨立管理自己的日志數據。
與 Grafana 集成
:- Loki 與 Grafana 緊密集成,可以直接在 Grafana 中查詢和可視化 Loki 中的日志數據。
- 這使得 Loki 成為了 Grafana 生態系統的一個重要組成部分。
低資源消耗
:- 相比于 ELK Stack,Loki 對資源的需求較低,更適合中小規模的團隊使用。
架構
Loki Server
:主服務器,負責接收日志數據、存儲數據和處理查詢。Alloy / Promtail
:一個輕量級的日志代理,用于收集日志文件并將日志數據發送給 Loki。- Alloy VS Promtail:基于 Loki 的日志采集架構對比與選型指南
- 本文使用
Loki4j
代替了Alloy / Promtail
Loki4j
是一個Java 日志庫(支持Logback \ Log4j
),它允許 Spring Boot 應用直接將日志推送到 Loki 服務器,無需通過日志代理轉發。- ?
Alloy / Promtail
的定位是日志采集代理,主要用于從日志文件中提取數據(如容器日志、系統日志),而Loki4j
直接在應用層完成日志發送,屬于兩種不同的數據采集方式。
Grafana
:用于查詢和顯示 Loki 中的日志數據的界面。Storage
:Loki 使用對象存儲(如 S3 或 GCS)來持久化日志數據,以降低存儲成本。
適用場景
大規模日志收集
:適用于需要處理大量日志數據的環境。實時日志查詢
:需要快速查詢和分析日志數據的場景。低成本日志存儲
:希望降低日志存儲成本的項目。
總結
Loki 是一個現代的日志管理系統,它簡化了日志數據的收集、存儲和查詢過程,特別適合那些需要高性能、可擴展性和成本效益的日志管理解決方案。
(二)Loki4j
Loki4j 是一個基于 Java 的日志框架
,它提供了一種簡單的方式來將日志數據發送到 Loki。Loki4j 旨在與 Loki 日志聚合系統無縫集成,使得 Java 應用程序能夠輕松地將日志數據發送到 Loki 以進行集中管理和分析。
特點
易于集成
:- Loki4j 提供了一個簡單的 API,可以很容易地與現有的 Java 應用程序集成。
- 支持 SLF4J 和 Logback 等流行的 Java 日志框架。
標簽支持
:- Loki4j 支持 Loki 的標簽查詢模型,允許用戶在日志消息中添加標簽,以便更好地組織和查詢日志數據。
異步日志記錄
:- Loki4j 支持異步日志記錄,可以提高應用程序的性能,因為它不會阻塞應用程序線程。
配置靈活
:- Loki4j 提供了靈活的配置選項,可以根據需要定制日志級別、日志格式等。
錯誤處理
:- Loki4j 包含了錯誤處理機制,可以處理網絡問題或其他異常情況,確保日志數據能夠可靠地發送到 Loki。
(三)Grafana
Grafana 是一款開源的數據可視化和分析平臺,主要用于可視化時間和序列數據,如監控指標、日志文件、應用程序跟蹤等
。它支持多種數據源,包括Prometheus、InfluxDB、MySQL、PostgreSQL、Elasticsearch、CloudWatch、Graphite等,以及自定義數據源。Grafana被廣泛應用于IT基礎架構監控、應用性能監控(APM)、物聯網(IoT)數據分析、業務指標監控等多個領域。
特點
直觀的界面
:Grafana提供了一個用戶友好的界面,用于創建和編輯儀表盤,使得數據可視化變得非常簡單,無需編程知識。豐富的圖表類型
:支持多種圖表類型,如折線圖、柱狀圖、餅圖、熱力圖、儀表盤、表格等,適合不同類型的視覺展示需求。動態和交互式面板
:面板可以配置為具有時間選擇器、下拉菜單、查詢編輯器等交互元素,使用戶能更靈活地探索數據。報警功能
:Grafana支持基于規則的報警系統,當數據達到預設的閾值時,可以通過電子郵件、Slack、PagerDuty等多種方式發送通知。注釋和事件
:用戶可以在圖表上添加注釋,記錄特定時間點發生的重要事件,有助于理解數據波動的原因。模板變量
:通過使用模板變量,可以創建動態儀表盤,允許用戶在不修改儀表盤的情況下,快速切換查看不同數據源或視角。插件生態
:Grafana擁有強大的社區支持,提供了大量的數據源插件、面板插件和應用插件,大大擴展了其功能和適用場景。API和腳本支持
:Grafana提供了完善的API接口,允許用戶通過腳本和外部應用自動化創建和管理儀表盤、數據源和用戶權限。團隊協作和權限管理
:支持多用戶訪問,可以為不同用戶或團隊分配不同的權限,促進團隊間的協作。
適用場景
IT運維監控
:實時監控服務器性能、網絡流量、應用程序健康狀況等。業務分析
:展現用戶行為、銷售數據、營銷活動效果等業務指標。物聯網數據可視化
:分析設備傳感器數據,監控物聯網系統運行狀態。日志分析
:結合Loki等日志管理系統,進行日志數據的實時查詢和可視化展示。
Grafana憑借其靈活性和易用性,成為了數據分析和監控領域的首選工具之一,幫助企業更好地理解數據、發現問題和制定決策。
二、組件配置
操作系統:Windows 11 家庭中文版
(一)Loki
-
下載地址:下載 Loki
官網:Loki 官網
注意是loki
,不要下載logcli
開頭的
這里使用的版本為 v2.9.9- 如果下載其他更高的版本,比如:v3.5.1,可能會在啟動Loki時報錯在配置文件中有不被識別的字段,這是版本兼容性導致的問題,若要升級為更新的版本,請參考版本發行說明自行修改下面的
loki-config.yaml
配置文件
- 如果下載其他更高的版本,比如:v3.5.1,可能會在啟動Loki時報錯在配置文件中有不被識別的字段,這是版本兼容性導致的問題,若要升級為更新的版本,請參考版本發行說明自行修改下面的
-
創建一個名為
loki-windows-amd64
的文件夾,將壓縮包中的loki-windows-amd64.exe
解壓到該文件夾中(不用點擊exe文件,點了也會閃退)
-
創建一個
config
文件夾,進入config
文件夾中,創建loki-config.yaml
配置文件,文件內容如下:server:# Loki 服務監聽的 HTTP 端口號http_listen_port: 3100schema_config:configs:- from: 2024-07-01# 使用 BoltDB 作為索引存儲store: boltdb# 使用文件系統作為對象存儲object_store: filesystem# 使用 v11 版本的 schemaschema: v11index:# 索引前綴prefix: index_# 索引周期為 24 小時period: 24hingester:lifecycler:# 設置本地 IP 地址address: 127.0.0.1ring:kvstore:# 使用內存作為 kvstorestore: inmemory# 復制因子設置為 1replication_factor: 1# 生命周期結束后的休眠時間final_sleep: 0s# chunk 的空閑期為 5 分鐘chunk_idle_period: 5m# chunk 的保留期為 30 秒chunk_retain_period: 30sstorage_config:boltdb:# BoltDB 的存儲路徑【自行替換】directory: C:\log system\loki-windows-amd64\BoltDBfilesystem:# 文件系統的存儲路徑【自行替換】directory: C:\log system\loki-windows-amd64\fileStorelimits_config:# 不強制執行指標名稱enforce_metric_name: false# 拒絕舊樣本reject_old_samples: true# 最大拒絕舊樣本的年齡為 168 小時reject_old_samples_max_age: 168h# 每個用戶每秒的采樣率限制為 32 MBingestion_rate_mb: 32# 每個用戶允許的采樣突發大小為 64 MBingestion_burst_size_mb: 64chunk_store_config:# 最大可查詢歷史日期為 28 天(672 小時),這個時間必須是 schema_config 中 period 的倍數,否則會報錯max_look_back_period: 672htable_manager:# 啟用表的保留期刪除功能retention_deletes_enabled: true# 表的保留期為 28 天(672 小時)retention_period: 672h
注意:
- 第三行“Loki 服務監聽的 HTTP 端口號”要記好,下面配置
Grafana
數據源時會用到,如果不使用上面給定的3100端口號,那么在下面配置Grafana
數據源時也需要一并修改 - yaml文件中的
BoltDB
的存儲路徑和文件系統
的存儲路徑自行替換為自己的路徑
- 第三行“Loki 服務監聽的 HTTP 端口號”要記好,下面配置
-
使用
cmd
進入loki-windows-amd64.exe
所在目錄下,執行啟動命令# 這個啟動命令是以后啟動Loki組件的專用命令,指定了配置文件 loki-windows-amd64.exe --config.file=config/loki-config.yaml
執行結果如下
下面的這幾個文件夾都是根據配置自動生成的
(二)Grafana
-
下載地址:Download Grafana,這里使用 11.1.0 版本
-
解壓
grafana-enterprise-11.1.0.windows-amd64.zip
得到grafana-v11.1.0
文件夾 -
進入
bin
目錄找到grafana-server.exe
程序雙擊運行
運行報錯請參考:
- Failed to get renderer plugin sources
- 目前還有一個關于
xychart
插件的報錯未找到解決方案,報錯信息:plugin xychart is already registered
,因其不影響使用,暫不深究,若大家有好的解決方案則可以在博文下留言,我會將解決方案及時更新博客中
-
程序運行成功后訪問:http://localhost:3000,初始賬戶:
admin/admin
(登錄后可以視個人情況選擇是否重置密碼)漢化教程請參考:Grafana 漢化調試
-
添加Loki數據源:選擇
Data sources
,點擊Add data source
,會出現很多數據源,找到Loki
數據源并單擊 -
設置監聽的數據源地址和HTTP請求頭
數據源地址(Loki配置文件里設置的):http://localhost:3100
Header:X-Scope-OrgID
Value:user1
設置
Header
的作用:理解Grafana中X-Scope-OrgID
的作用與配置
-
保存并測試:點擊
save & test
,出現下面紅框中的提示即說明數據源連接成功
注意:如果
save&test
報錯可能是Loki服務初始化還未完成,驗證Loki初始化是否完成訪問:http://localhost:3100/ready,如果顯示ready
即初始化完成
三、項目搭建
-
創建SpringBoot項目:Java 17 + SpringBoot 3.0.2
慎選 Java8 + SpringBoot2,可能會出現依賴問題或配置錯誤導致的Loki4jAppender類無法被正確加載,從而導致項目啟動報錯
-
添加POM依賴
<!--Loki 日志收集--> <dependency><groupId>com.github.loki4j</groupId><artifactId>loki-logback-appender</artifactId><version>1.5.1</version> </dependency> <!--Loki 日志發送http請求和響應工具--> <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version> </dependency> <!--提供 @Slf4j 注解的依賴庫--> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.32</version><scope>provided</scope> </dependency>
-
在
resources
目錄下創建logback-spring.xml
文件<?xml version="1.0" encoding="UTF-8"?> <configuration><!-- 彩色控制臺控制 --><substitutionProperty name="log.pattern" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) ${PID:-} %clr(---){faint} %clr(%-80.80logger{79}){cyan} %clr(:){faint} %m%n%wEx"/><substitutionProperty name="log.pattern.no" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) ${PID:-} %clr(---){faint} %clr(%-80.80logger{79}){cyan} %clr(:){faint} %m%n%wEx"/><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/><conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/><conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/><springProperty scope="context" name="LOG_FILE_DIR" source="logback.log-file-dir" defaultValue="log"/><!-- 控制臺輸出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${log.pattern}</pattern></encoder></appender><springProperty scope="context" name="url" source="loki.url" defaultValue="http://localhost:3100/loki/api/v1/push"/><springProperty scope="context" name="env" source="loki.label.env" defaultValue="dev"/><springProperty scope="context" name="jobName" source="loki.label.job-name" defaultValue="my-app"/><springProperty scope="context" name="hostIp" source="loki.label.host-ip" defaultValue="localhost"/><springProperty scope="context" name="orgId" source="loki.org-id" defaultValue="default-org"/><appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender"><http class="com.github.loki4j.logback.ApacheHttpSender"><url>${url}</url><tenantId>${orgId}</tenantId></http><format><label><pattern>application=${jobName},env=${env},host=${hostIp},level=%level</pattern></label><message><pattern>{"timestamp": "%d{yyyy-MM-dd HH:mm:ss.SSS}", "level": "%level", "logger": "%logger{36}", "thread": "%thread", "message": "%msg%n"}</pattern></message><sortByTime>true</sortByTime></format></appender><!-- 使用異步方式將日志推送至Loki --><appender name="ASYNC_LOKI" class="ch.qos.logback.classic.AsyncAppender"><!-- 隊列大小設置,根據實際需要調整 --><queueSize>512</queueSize><!-- 丟棄策略,當隊列滿時采取的操作 --><discardingThreshold>0</discardingThreshold><neverBlock>true</neverBlock><!-- 實際的Loki Appender --><appender-ref ref="LOKI" /></appender><appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>DENY</onMatch><onMismatch>ACCEPT</onMismatch></filter><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${log.pattern.no}</pattern></encoder><!--滾動策略--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--路徑--><fileNamePattern>${LOG_FILE_DIR}/info.%d.log</fileNamePattern><!--保留30天日志--><maxHistory>30</maxHistory></rollingPolicy></appender><appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level></filter><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${log.pattern.no}</pattern></encoder><!--滾動策略--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--路徑--><fileNamePattern>${LOG_FILE_DIR}/error.%d.log</fileNamePattern><!--保留30天日志--><maxHistory>30</maxHistory></rollingPolicy></appender><root level="info"><appender-ref ref="STDOUT" /><appender-ref ref="fileInfoLog" /><appender-ref ref="fileErrorLog" /><appender-ref ref="ASYNC_LOKI" /></root></configuration>
-
配置
application.yml
文件spring:application:name: grafana-project# Loki 日志配置 loki:# Loki 服務的 URL,用于推送日志數據url: http://localhost:3100/loki/api/v1/push# 標簽配置,用于標識日志來源的額外信息label:# 環境標簽,標識當前運行的環境,例如開發環境env: dev# 服務名稱標簽,標識日志來源的服務名稱job-name: my-service# 主機 IP 標簽,標識日志來源的主機 IP 地址host-ip: localhost# 組織 ID,用于多租戶環境中標識日志所屬的組織org-id: user1
-
啟動類添加日志注解和日志打印代碼
import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@Slf4j @SpringBootApplication public class GrafanaProjectApplication {public static void main(String[] args) {SpringApplication.run(GrafanaProjectApplication.class, args);log.info("GrafanaProjectApplication started");System.out.println("GrafanaProjectApplication started");}}
-
啟動SpringBoot項目,然后去 Grafana 查詢日志信息:選擇
Explore
,在Label filters
中下拉選擇level=INFO
,然后點擊右上角的Run query
,就能看到查詢到的日志數據了
注意:
- 只有log方式記錄的日志才會發送到Grafana,控制臺輸出的不會發送
- 剛啟動組件時,后臺需要一定時間加載,這時候是無法記錄日志的
參考文章
springboot+Loki+Loki4j+Grafana搭建輕量級日志系統
【監控儀表系統】Grafana 中文入門教程 | 構建你的第一個儀表盤