mcpField
L
loki

loki

github.com/grafanaクラウド・DevOps2957.8k 回インストール1 日前に更新
リポジトリ

loki について

lokiは、ログの検索や分析を行う開発者・運用担当者向けに、Grafana Lokiのログ集約とLogQLクエリを解説するスキルです。ラベルによる絞り込み、解析、メトリクス計算、ログ取り込み方法を扱います。

主な機能

  1. 01ラベルによるログストリーム選択
  2. 02LogQLでのログ絞り込みと解析
  3. 03ログからのメトリクス・集計計算
  4. 04Alloy、Kubernetes、HTTPによるログ送信設定

活用シーン

  1. 01アプリと環境別のエラーログ検索
  2. 02サービスのリクエスト率・エラー率計測
  3. 03遅いリクエストとHTTP 5xxログの検索
  4. 04ログ内の認証情報漏えいパターン検出

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/grafana/skills --skill loki

インストール後、Claude Code で/lokiを入力して読み込まれたか確認します。

詳細

Grafana Loki - ログ集約

ドキュメント: https://grafana.com/docs/loki/latest/

メタデータ(ラベル)のみをインデックス化し、ログの全文はインデックス化しないため、全文検索システムと比べて大幅に低コストです。

LogQL クイックリファレンス

ログストリームセレクター(すべてのクエリで必須)
{app="nginx"}                        # exact match
{app!="nginx"}                       # not equal
{app=~"nginx|apache"}               # regex match
{app!~"debug.*"}                     # regex not match
{app="nginx", env="prod"}           # AND (multiple labels)
行フィルター(パイプラインのステージ 1 - パフォーマンスのため最初に配置)
{app="nginx"} |= "error"            # contains string
{app="nginx"} != "info"             # does not contain
{app="nginx"} |~ "error|warn"       # regex match
{app="nginx"} !~ "health.*check"    # regex not match
{app="nginx"} |= `"status":5`       # backtick avoids escaping
パーサー
# 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 (positional, _ discards)
{app="nginx"} | pattern `<ip> - - <_> "<method> <uri> <_>" <status> <bytes>`

# Regexp (named capture groups)
{app="nginx"} | regexp `(?P<method>\w+) (?P<path>\S+) HTTP/(?P<version>\S+)`

# Unpack (unwrap Promtail packed labels)
{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

メトリクスクエリ

ログ範囲の集計
# Requests per second
rate({app="nginx"}[5m])

# Total log lines in window
count_over_time({app="nginx"}[1h])

# Bytes per second
bytes_rate({app="nginx"}[5m])

# Total bytes
bytes_over_time({app="nginx"}[1h])

# Returns 1 if no logs in range (for absence alerting)
absent_over_time({app="nginx"}[5m])
集約
# Error rate by service
sum(rate({env="prod"} |= "error" [5m])) by (app)

# Top 5 most active services
topk(5, sum(rate({env="prod"}[5m])) by (app))

# Total errors across all services
sum(count_over_time({env="prod"} |= "error" [5m]))
アンラップ範囲の集計(ログから取得した数値)
# Average request duration from logfmt
avg_over_time({app="api"} | logfmt | unwrap duration [5m])

# 95th percentile latency
quantile_over_time(0.95, {app="api"} | logfmt | unwrap duration [5m]) by (app)

# Sum of bytes from JSON logs
sum_over_time({app="api"} | json | unwrap bytes [5m])

# With conversion (duration string → seconds)
avg_over_time({app="api"} | logfmt | unwrap duration | duration_seconds [5m])
オフセット修飾子
# Compare current rate vs 1 hour ago
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"]
      ]
    }]
  }'

アーキテクチャ

Push path:  Client → Distributor → Ingester (WAL) → Object Storage (chunks)
Read path:  Query → Query Frontend → Querier → Ingester + Store (chunks)

コンポーネント:

  • Distributor:受信したログストリームを検証し、ハッシュ化します
  • Ingester:チャンクをメモリにバッファリングし、オブジェクトストレージにフラッシュします
  • Querier:LogQL クエリを実行します
  • Query Frontend:クエリをキャッシュ、分割し、並列化します
  • Compactor:保持期間と重複排除を管理します

参考資料

コメント