loki

loki

熱門

Grafana Loki 日誌聚合與 LogQL 查詢語言。涵蓋 LogQL 語法(日誌查詢、指標查詢、標籤匹配、行過濾器、解析器:json/logfmt/pattern/regexp/unpack、標籤過濾器、line_format)、Loki 架構、透過 Alloy/Promtail/Fluent Bit 進行日誌擷取、結構化中繼資料,以及 Logs Drilldown。適用於撰寫 LogQL 查詢、設定 Loki、排錯日誌管線或分析日誌時使用。

204星標
17分支
更新於 2026/7/28
SKILL.md
唯讀
名稱
loki
描述

Grafana Loki 日誌聚合與 LogQL 查詢語言。涵蓋 LogQL 語法(日誌查詢、指標查詢、標籤匹配、行過濾器、解析器:json/logfmt/pattern/regexp/unpack、標籤過濾器、line_format)、Loki 架構、透過 Alloy/Promtail/Fluent Bit 進行日誌擷取、結構化中繼資料,以及 Logs Drilldown。適用於撰寫 LogQL 查詢、設定 Loki、排錯日誌管線或分析日誌時使用。

Grafana Loki - 日誌聚合

文件https://grafana.com/docs/loki/latest/

僅索引中繼資料(標籤),而非完整日誌內容——比全文檢索系統便宜許多。

LogQL 快速參考

日誌串流選擇器(每個查詢必填)

{app="nginx"}                        # 精確比對
{app!="nginx"}                       # 不等於
{app=~"nginx|apache"}               # 正規表示式比對
{app!~"debug.*"}                     # 正規表示式不匹配
{app="nginx", env="prod"}           # AND(多個標籤)

行過濾器(管線階段 1 - 為效能應優先放置)

{app="nginx"} |= "error"            # 包含字串
{app="nginx"} != "info"             # 不包含
{app="nginx"} |~ "error|warn"       # 正規表示式比對
{app="nginx"} !~ "health.*check"    # 正規表示式不匹配
{app="nginx"} |= `"status":5`       # 反引號避免跳脫

解析器

# JSON
{app="api"} | json
{app="api"} | json status="http_status", path="request.path"

# Logfmt
{app="api"} | logfmt
{app="api"} | logfmt --strict
{app="api"} | logfmt --keep-empty

# Pattern(位置式,_ 表示捨棄)
{app="nginx"} | pattern `<ip> - - <_> "<method> <uri> <_>" <status> <bytes>`

# Regexp(具名捕獲群組)
{app="nginx"} | regexp `(?P<method>\w+) (?P<path>\S+) HTTP/(?P<version>\S+)`

# Unpack(解開 Promtail 打包的標籤)
{app="api"} | unpack

標籤過濾器(解析器之後)

{app="api"} | json | status >= 500
{app="api"} | json | status == 200 and method != "OPTIONS"
{app="api"} | logfmt | duration > 1s
{app="api"} | json | level =~ "error|warn"
{app="api"} | json | bytes > 20MB
{app="api"} | json | path != "/healthz"

行格式

{app="api"} | json | line_format "{{.method}} {{.path}} -> {{.status}} ({{.duration}})"
{app="api"} | logfmt | line_format `{{.level | upper}}: {{.msg}}`

標籤格式

{app="api"} | logfmt | label_format new_name=old_name
{app="api"} | logfmt | label_format severity=level, svc=app
{app="api"} | logfmt | label_format msg=`{{.level}}: {{.message}}`

捨棄/保留標籤

{app="api"} | json | drop filename, level="debug"
{app="api"} | json | keep level, status, method

去除顏色碼

{app="cli-tool"} | decolorize

指標查詢

日誌範圍聚合

# 每秒請求數
rate({app="nginx"}[5m])

# 時間視窗內的日誌行總數
count_over_time({app="nginx"}[1h])

# 每秒位元組數
bytes_rate({app="nginx"}[5m])

# 總位元組數
bytes_over_time({app="nginx"}[1h])

# 若範圍內無日誌則回傳 1(用於缺失告警)
absent_over_time({app="nginx"}[5m])

聚合

# 依服務的錯誤率
sum(rate({env="prod"} |= "error" [5m])) by (app)

# 前 5 名最活躍服務
topk(5, sum(rate({env="prod"}[5m])) by (app))

# 所有服務的錯誤總數
sum(count_over_time({env="prod"} |= "error" [5m]))

解包範圍聚合(從日誌中提取數值)

# 從 logfmt 取得的平均請求持續時間
avg_over_time({app="api"} | logfmt | unwrap duration [5m])

# 第 95 百分位延遲
quantile_over_time(0.95, {app="api"} | logfmt | unwrap duration [5m]) by (app)

# 從 JSON 日誌取得的位元組總和
sum_over_time({app="api"} | json | unwrap bytes [5m])

# 含轉換(持續時間字串 → 秒)
avg_over_time({app="api"} | logfmt | unwrap duration | duration_seconds [5m])

偏移修飾符

# 比較當前速率與 1 小時前
rate({app="nginx"}[5m]) / rate({app="nginx"}[5m] offset 1h)

實用範例

錯誤率告警查詢

sum(rate({env="prod"} |= "error" [5m])) by (service)
/
sum(rate({env="prod"}[5m])) by (service)
> 0.05

慢請求

{app="api"} | logfmt | duration > 1s | line_format "SLOW: {{.method}} {{.path}} {{.duration}}"

HTTP 5xx 錯誤含詳細資訊

{app="nginx"} | pattern `<ip> - - <_> "<method> <uri> <_>" <status> <bytes>` | status >= 500

憑證外洩偵測

{namespace="prod"} |~ `https?://\w+:\w+@`

傳送日誌到 Loki

透過 Grafana Alloy

loki.source.file "app" {
  targets    = [{__path__ = "/var/log/app/*.log", job = "app"}]
  forward_to = [loki.process.parse.receiver]
}

loki.process "parse" {
  forward_to = [loki.write.cloud.receiver]
  stage.json {
    expressions = { level = "level", msg = "message" }
  }
  stage.labels {
    values = { level = "" }
  }
  stage.drop {
    expression = ".*healthcheck.*"
  }
}

loki.write "cloud" {
  endpoint {
    url = "https://logs-xxx.grafana.net/loki/api/v1/push"
    basic_auth {
      username = sys.env("LOKI_USER")
      password = sys.env("GRAFANA_API_KEY")
    }
  }
  external_labels = { cluster = "prod" }
}

透過 Kubernetes(Alloy DaemonSet)

discovery.kubernetes "pods" {
  role = "pod"
}

loki.source.kubernetes "pods" {
  targets    = discovery.kubernetes.pods.targets
  forward_to = [loki.write.cloud.receiver]
}

Loki HTTP Push API

curl -X POST https://logs-xxx.grafana.net/loki/api/v1/push \
  -u "user:apikey" \
  -H 'Content-Type: application/json' \
  -d '{
    "streams": [{
      "stream": { "app": "myapp", "env": "prod" },
      "values": [
        ["1609459200000000000", "log line here"]
      ]
    }]
  }'

架構

推送路徑:  Client → Distributor → Ingester (WAL) → Object Storage (chunks)
讀取路徑:  Query → Query Frontend → Querier → Ingester + Store (chunks)

元件:

  • Distributor:驗證並雜湊傳入的日誌串流
  • Ingester:在記憶體中緩衝區塊,並刷新到物件儲存
  • Querier:執行 LogQL 查詢
  • Query Frontend:快取、分割並平行化查詢
  • Compactor:管理保留與重複資料刪除

參考資料