將 Spring Boot Log 透過 Logstash 導入 Elasticsearch
在 Spring Boot 應用程式中,Log 通常會先輸出到 Console 或檔案,方便開發與單機排查問題。不過當服務數量變多、部署環境變複雜後,單靠各主機上的 Log 檔案會讓查詢與追蹤變得不方便。這時可以透過 Logstash 接收 Spring Boot 輸出的結構化 Log,再寫入 Elasticsearch,讓後續查詢、分析與視覺化更加集中。
本文會記錄如何在 Linux 環境安裝 Logstash,設定 Logstash 將 TCP 收到的 JSON Log 寫入 Elasticsearch,最後再於 Spring Boot 的 logback 設定中加入 Logstash Appender,讓應用程式 Log 可以送進 Elasticsearch。
安裝必要套件與匯入 PGP 金鑰
首先更新本地套件清單,並安裝新增 APT 儲存庫時會用到的必要工具。接著下載 Elastic 官方 PGP 金鑰,並轉成 keyring 格式存放在系統路徑中,供後續套件來源驗證使用。
1 | # 更新本地套件清單並安裝必備工具 |
加入 APT 儲存庫
接著將 Elastic 9.x 的 APT 儲存庫加入系統來源清單。這裡會指定前面匯入的 keyring,讓 apt 在安裝套件時能驗證來源。
1 | echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/9.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-9.x.list |
安裝 Logstash
儲存庫加入完成後,再次更新套件清單,接著安裝 Logstash。
1 | sudo apt-get update |
啟動 Logstash 服務
套件安裝完成後,先重新載入 systemd 設定,然後將 Logstash 設定為開機自動啟動,並立即啟動服務。若需要觀察 Logstash 啟動狀態,可以使用 journalctl 查看服務日誌。
1 | sudo systemctl daemon-reload |
設定 Logstash conf
Logstash 啟動後,接著設定 pipeline。這份設定會透過 TCP 監聽 5044 port,使用 json_lines codec 接收 Spring Boot 傳來的 JSON Log。
在 filter 階段,若 Log 事件中沒有 application 欄位,會補上 unknown-app;若有提供 application,則會轉成小寫,並將不符合索引名稱使用習慣的字元替換成 -。最後 output 會將資料寫入 Elasticsearch,並依照 application 與日期產生索引名稱。
本文範例將 Logstash pipeline 設定放在 /etc/logstash/conf.d/app-logstash.conf。建立或編輯這個檔案後,將下方設定內容寫入其中。
1 | input { |
如果 Logstash 連線 Elasticsearch 時出現憑證錯誤,可以將 Elasticsearch 的 CA 憑證複製到 Logstash 可讀取的位置,並調整目錄權限。
這個錯誤通常是因為 Elasticsearch 啟用 HTTPS 後,Logstash 需要透過 CA 憑證驗證 Elasticsearch 的 TLS 憑證。如果 ssl_certificate_authorities 指定的憑證不存在,或是 Logstash 服務帳號沒有讀取權限,就會在啟動 pipeline 或連線 Elasticsearch 時發生憑證驗證失敗。
以下指令會先建立 Logstash 專用的憑證目錄,接著把 Elasticsearch 安裝時產生的 http_ca.crt 複製到該目錄,最後將目錄擁有者調整為 logstash,確保 Logstash 服務可以正常讀取憑證。
1 | # 建立 Logstash 存放 Elasticsearch CA 憑證的目錄 |
Logstash 正常啟動後,可以在服務日誌中看到 pipeline 已經開始執行,並且 TCP input listener 成功綁定到 0.0.0.0:5044。畫面中的 Pipeline started、Starting tcp input listener,以及 Pipelines running {:count=>1, :running_pipelines=>[:main]} 都代表主要 pipeline 已經載入並處於執行中狀態。此時 Spring Boot 應用程式只要將 Log 傳送到 Logstash 主機的 5044 port,Logstash 就可以接收事件並依照前面的 output 設定寫入 Elasticsearch。
設定 Spring Boot Log
Logstash 端設定完成後,接著在 Spring Boot 的 logback 設定中加入 Logstash Appender。這裡使用 LogstashTcpSocketAppender,透過 ${LOGSTASH_DESTINATION} 指定 Logstash 位址,並在 encoder 中加入自訂欄位,讓每筆 Log 都帶有應用程式名稱與環境資訊。
1 | <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender"> |
接著將 LOGSTASH appender 掛到 root logger。這樣 Spring Boot 在輸出 Console 與 File Log 的同時,也會把同一份 Log 傳送到 Logstash。
1 | <root level="${ROOT_LOG_LEVEL}"> |
完成以上設定後,Spring Boot 的 Log 會先透過 TCP 傳送到 Logstash,再由 Logstash 寫入 Elasticsearch。後續只要依照 application-YYYY.MM.dd 的索引格式查詢,就可以針對不同應用程式與日期快速篩選 Log。