跳到主要內容
節省工具箱Jason Tools
技術文章

Graylog 查詢最早記錄時間的做法

Jason Cheng 發布 瀏覽 1 次
Graylog 查詢最早記錄時間的做法
本文目錄
  1. 方法比較
  2. Index Ranges API
  3. 直接查 OpenSearch
  4. Views 匯出 API
  5. Universal Search(Legacy)
  6. 結論
  7. 參考資料

在開發 jt-glogarch(Graylog Open 的記錄歸檔工具)時,有一個需求是:查出每個 index set、每個 stream 最早一筆記錄的時間,用來判斷要從哪裡開始歸檔、還有多少資料沒歸檔。

這種「只要一個值」的指標型查詢,寫法不同,傳回的資料量可以差上百倍。只查一次感覺不出來,但要批次遍歷所有 index set 時差距就很明顯。這篇整理我比較過的幾種做法,以及官方 API 的幾個細節。

方法比較

方法查詢對象傳回大小適用情境
Index Ranges APIGraylog(MongoDB 裡的記錄)小,不查 OpenSearch依 index 判斷時間範圍,最省
直接查 OpenSearchOpenSearch約 100 bytes要精確到某個 index pattern,批次掃描
Views 匯出 APIGraylog約 50 bytes(CSV)依 stream 查,走 Graylog 權限
Universal Search(Legacy)Graylog數百 bytes(JSON)舊程式相容

Index Ranges API

很多人不知道,Graylog 本身就有記錄每個 index 的時間範圍(index range),存在 MongoDB 裡,搜尋時就是靠它決定要查哪些 index。所以如果只是要知道「某個 index set 最早的資料是什麼時候」,根本不用查 OpenSearch:

curl -s -u "your-token:token" -H "Accept: application/json" \
  "https://graylog.example.com/api/system/indices/ranges"

傳回每個 index 的 index_name、begin、end、calculated_at。依 index set 的前綴(例如 graylog_)篩選,取最小的 begin 就是最早的時間。

查單一 index:

curl -s -u "your-token:token" -H "Accept: application/json" \
  "https://graylog.example.com/api/system/indices/ranges/graylog_120"

注意:index range 是在 index 輪替(rotate)時計算的,目前正在寫入的 index 範圍會持續變動;如果懷疑資料不準,可以在「System → Indices」對該 index set 重新計算,或呼叫 POST /api/system/indices/ranges/rebuild。另外它只能精確到 index,無法依 stream 區分。

直接查 OpenSearch

要精確查某個 index pattern 的最早一筆,直接打 OpenSearch 最划算。重點是不要拿 _source,改用 docvalue_fields,連 _source 解壓縮都省掉:

curl -s -u "admin:your-password" \
  "https://opensearch.example.com:9200/graylog_*/_search?filter_path=hits.hits.fields.timestamp" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 1,
    "sort": [{"timestamp": "asc"}],
    "_source": false,
    "docvalue_fields": ["timestamp"],
    "track_total_hits": false
  }'

幾個壓縮重點:

  • _source: false + docvalue_fields
    直接從 doc values 讀時間欄位,不用讀取與解壓縮整筆訊息
  • filter_path
    把回應裁到只剩需要的欄位,整個回應可以壓到 100 bytes 以內
  • track_total_hits: false
    不計算符合的總筆數,大 index 上可以省下不少時間

傳回結果長這樣:

{"hits":{"hits":[{"fields":{"timestamp":["2024-03-15 08:23:11.000"]}}]}}

也可以用 min 聚合,語意更直接:

curl -s -u "admin:your-password" \
  "https://opensearch.example.com:9200/graylog_*/_search?filter_path=aggregations.earliest.value_as_string" \
  -H "Content-Type: application/json" \
  -d '{"size": 0, "aggs": {"earliest": {"min": {"field": "timestamp"}}}}'

注意:OpenSearch 帳密請勿直接寫在指令或腳本裡,批次腳本可以改用 .netrc 或環境變數;憑證是自簽的話,測試時才用 -k,正式環境請指定 CA(--cacert)。另外直接查 OpenSearch 會繞過 Graylog 的權限控管,帳號要限縮在唯讀。

Views 匯出 API

如果要依 stream 查,或是不想把 OpenSearch 帳號交給程式,就走 Graylog 的 API。/api/views/search/messages 是 Graylog 匯出訊息的端點,可以用 fields_in_order 指定只傳回 timestamp:

curl -s -u "your-token:token" \
  -H "X-Requested-By: cli" \
  -H "Content-Type: application/json" \
  -H "Accept: text/csv" \
  -X POST "https://graylog.example.com/api/views/search/messages" \
  -d '{
    "streams": ["STREAM_ID"],
    "query_string": {"type": "elasticsearch", "query_string": "*"},
    "timerange": {"type": "relative", "range": 0},
    "fields_in_order": ["timestamp"],
    "limit": 1
  }'

傳回的就是 CSV,沒有任何包裝,大約 50 bytes:

"timestamp"
"2024-03-15T08:23:11.000Z"

幾個細節:

  • 不需要也不能指定排序
    我看了 Graylog 原始碼,這個端點的請求格式沒有 sort 欄位,匯出時一律依 timestamp 由舊到新排序(加上 tiebreaker 欄位),所以 limit: 1 拿到的就是最早一筆
  • range: 0 代表全部時間
  • fields_in_order 只放 timestamp
    預設會帶 timestamp、source、message,不指定的話傳回量會大很多
  • X-Requested-By 標頭
    Graylog 的 POST 請求一定要帶,內容隨意,沒帶會被拒絕

Universal Search(Legacy)

/api/search/universal/relative 是舊版的搜尋 API,在 Graylog 的 API 文件裡已經歸類在 Legacy,新寫的程式不建議再用,但舊腳本可能還在跑,還是說明一下:

curl -s -u "your-token:token" -H "Accept: application/json" \
  "https://graylog.example.com/api/search/universal/relative" -G \
  --data-urlencode "query=*" \
  --data-urlencode "range=0" \
  --data-urlencode "limit=1" \
  --data-urlencode "sort=timestamp:asc" \
  --data-urlencode "fields=timestamp" \
  --data-urlencode "streams=STREAM_ID"

注意:這裡一定要用 JSON(Accept: application/json)。這個 API 的 CSV 版本沒有 sort 參數,加了也不會生效;而 JSON 版本沒指定排序時預設是 timestamp 由新到舊,忘了加 sort=timestamp:asc 會拿到最新一筆而不是最早一筆。

結論

查最早時間這種指標型查詢,我的選擇順序是:

  1. 只需要精確到 index:Index Ranges API,完全不碰 OpenSearch
  2. 要精確、要批次掃描:直接查 OpenSearch,搭配 docvalue_fields 與 filter_path
  3. 要依 stream、要走 Graylog 權限:Views 匯出 API,記得用 CSV

jt-glogarch 歸檔掃描就是用這幾種方式組合,掃完全部 index set 的時間比原本快很多。

參考資料

Jason Cheng

Jason Cheng

企業開源技術顧問,專注架構規劃與實務導入

關於作者 →

延伸閱讀