AI

OSSログ管理比較:ELK Stack vs Loki vs Graylog でSplunkを脱却する

オープンソースラボ編集部2026年6月13日

OSSログ管理比較:ELK Stack vs Loki vs Graylog でSplunkを脱却する

Splunk(月$150/GB〜)・Datadog Log Management(月$0.10/GB〜)・Sumo Logic(月$3/GB〜)に対して、ELK Stack(Elasticsearch + Logstash + Kibana)・Loki(Grafanaのログ集約)・Graylog(構造化ログ管理)はOSSでログ管理基盤を構築できます。

OSSログ管理を選ぶ理由

  • コスト: Splunk 100GB/日=$15,000/月。Lokiセルフホストはストレージ代のみ
  • データ主権: 本番ログに機密情報(認証トークン・個人情報)が含まれる場合に社内保持
  • Grafana統合: Lokiはメトリクス(Prometheus)・トレース(Tempo)と同じGrafana UIで表示
  • スケーラビリティ: LokiはS3にログを保存し、ほぼ無制限にスケール

主要ツールの概要

Loki(Grafana Loki)

2018年公開、Go製のOSSです。GitHubスター24k+。**「Prometheusのログ版」**として設計され、ログのインデックスはラベル(Kubernetes Pod名・サービス名等)のみを持ちます。Elasticsearchと比べてストレージコストが1/10〜1/50になる点が最大の特長です。

# docker-compose.yml - Grafana + Loki + Promtail スタック
version: '3.8'
services:
  loki:
    image: grafana/loki:2.9.4
    restart: unless-stopped
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/config.yaml
    volumes:
      - ./loki-config.yaml:/etc/loki/config.yaml
      - loki_data:/loki

  promtail:
    image: grafana/promtail:2.9.4
    restart: unless-stopped
    volumes:
      - /var/log:/var/log:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - ./promtail-config.yaml:/etc/promtail/config.yaml
    command: -config.file=/etc/promtail/config.yaml

  grafana:
    image: grafana/grafana:10.4.0
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: your-password
      GF_FEATURE_TOGGLES_ENABLE: traceqlEditor
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana-provisioning:/etc/grafana/provisioning

volumes:
  loki_data:
  grafana_data:
# loki-config.yaml - Loki設定(ローカルストレージ)
auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory

schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

limits_config:
  retention_period: 30d   # 30日間保持

compactor:
  working_directory: /loki/compactor
  retention_enabled: true
# promtail-config.yaml - Dockerコンテナのログを収集
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  # Dockerコンテナのログを自動収集
  - job_name: docker
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        refresh_interval: 5s
    relabel_configs:
      - source_labels: [__meta_docker_container_name]
        target_label: container
      - source_labels: [__meta_docker_container_log_stream]
        target_label: logstream
      - source_labels: [__meta_docker_container_label_com_docker_compose_service]
        target_label: service

  # アプリケーションログファイルを収集
  - job_name: app-logs
    static_configs:
      - targets:
          - localhost
        labels:
          job: myapp
          env: production
          __path__: /var/log/myapp/*.log
    pipeline_stages:
      - json:
          expressions:
            level: level
            message: message
            trace_id: trace_id
      - labels:
          level:
          trace_id:
# LokiのHTTP APIでログをクエリ(Python)
import requests
from datetime import datetime, timezone, timedelta

LOKI_URL = 'http://localhost:3100'

def query_logs(
    logql: str,
    start: datetime = None,
    end: datetime = None,
    limit: int = 100,
) -> list:
    '''LogQLクエリでLokiからログを取得'''
    now = datetime.now(timezone.utc)
    params = {
        'query': logql,
        'start': int((start or now - timedelta(hours=1)).timestamp() * 1e9),
        'end': int((end or now).timestamp() * 1e9),
        'limit': limit,
        'direction': 'backward',
    }
    resp = requests.get(f'{LOKI_URL}/loki/api/v1/query_range', params=params)
    resp.raise_for_status()
    result = resp.json()
    logs = []
    for stream in result['data']['result']:
        for ts, line in stream['values']:
            logs.append({'timestamp': ts, 'log': line, 'labels': stream['stream']})
    return logs

# 直近1時間のERRORログを取得
error_logs = query_logs(
    logql='{service="myapp", env="production"} |= `ERROR` | json | level="error"',
    limit=50,
)
print(f'{len(error_logs)}件のエラーログ:')
for log in error_logs[:5]:
    print(f"  {log['log'][:100]}")

# 特定のtrace_idのログを追跡(分散トレーシングと連携)
trace_logs = query_logs(
    logql='{service=~".*"} | json | trace_id="abc123def456"',
)
print(f'トレース abc123def456: {len(trace_logs)}件のログスパン')

ELK Stack(Elasticsearch + Logstash + Kibana)

2012〜、Java/Node.js製のOSSです(Elasticsearch/Kibanaは2021年にライセンス変更、OSSフォークのOpenSearchも存在)。フルテキスト検索・複雑なログ集計・機械学習異常検知が必要な場合に選択されます。大量ログの分析ダッシュボードが充実しています。

# docker-compose.yml - ELK Stack(シンプル構成)
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
    restart: unless-stopped
    environment:
      discovery.type: single-node
      ES_JAVA_OPTS: -Xms1g -Xmx1g
      xpack.security.enabled: "false"
    volumes:
      - es_data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"

  logstash:
    image: docker.elastic.co/logstash/logstash:8.13.0
    restart: unless-stopped
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf

  kibana:
    image: docker.elastic.co/kibana/kibana:8.13.0
    restart: unless-stopped
    ports:
      - "5601:5601"
    environment:
      ELASTICSEARCH_HOSTS: http://elasticsearch:9200

volumes:
  es_data:

機能比較表

比較項目LokiELK StackGraylog
ストレージ効率★★★(最高)★☆☆(高コスト)★★☆
検索性能★★☆(ラベル検索)★★★(全文検索)★★☆
Grafana統合✅(ネイティブ)△(プラグイン)
最小RAM512MB2GB〜1GB〜
GitHub Stars24k+70k+(OpenSearch)8k+

ログ管理はDevOpsカテゴリ/categories/devopsのPrometheus・SigNozと組み合わせてメトリクス・ログ・トレースの3本柱のオブザーバビリティ基盤を構築します。セキュリティカテゴリ/categories/securityのWazuhとGraylogを統合してSIEM(セキュリティ情報イベント管理)基盤を構築するケースも多くあります。

FAQ

Q. LokiとElasticsearchのストレージコストの違いを具体的に教えてください。

A. 同じログ量(1GB/日)での比較: Elasticsearch: テキストのインデックス生成でRAWログの3〜5倍のストレージ消費→5GB/日、30日保持で150GB、AWS EBS $0.10/GB=$15/月。Loki: ラベルのみインデックス化→ログはgzip圧縮してS3に保存、圧縮後は原寸の10〜20%→200MB/日→30日=6GB、S3 $0.025/GB=$0.15/月。つまりLoki(S3)はElasticsearchの100倍以上コスト効率が良いケースがあります。ただしElasticsearchは任意のフィールドでの全文検索が可能で、Lokiは指定ラベル+grepのみ。非構造化ログのアドホック分析が多い場合はElasticsearchが向いています。

Q. Next.jsアプリのサーバーログをLokiに送るには?

A. Next.jsのAPIルートやServer Actionsのログは複数の方法で送れます。①winston + winston-loki: npm install winston winston-loki→winstonのTransportにLokiを追加(HTTP Push API)②Promtail: Next.jsをDockerで動かしている場合はコンテナのstdoutを自動収集③OpenTelemetry Logs: @opentelemetry/sdk-logs + @opentelemetry/exporter-logs-otlp-httpでLoki互換エンドポイントにPush。最もシンプルな方法: console.log(JSON.stringify({level:"info",message:"...",trace_id:"..."}))でJSON出力→PromtailのJSON pipelineでラベル抽出→Loki自動収集。

Q. Lokiのログ保存期間(Retention)を設定するには?

A. Lokiの設定ファイル(loki-config.yaml)のlimits_config.retention_periodで設定: 30d(30日)・90d(90日)。Compactorが自動で期限切れチャンクを削除します(compactor.retention_enabled: trueが必要)。S3バックエンドを使う場合はS3のライフサイクルポリシーでも制御可能(より安価に長期保存→Glacierへ移行)。注意: Lokiのretentionはグローバル設定のほか、Tenantごとにも設定できます(ruler_remote_write_headersでMulti-tenancy有効化)。

Q. GraylogをAD(Active Directory)と連携してログアクセスを制御するには?

A. Graylog → System → Authentication → Active Directory を選択。設定: AD/LDAPのホスト名・ポート・Base DN(DC=yourcompany,DC=com)・検索フィルタ((&(objectClass=user)(sAMAccountName=%s)))・管理者DNとパスワード。グループマッピング: ADのセキュリティグループ(例: GraylogAdminsGraylogReaders)をGraylogのロールにマッピング。これで社員のADアカウントでGraylogにSSOログインでき、部門ごとにストリームへのアクセス権を制御できます。

まとめ

ユースケース推奨ツール
コスト最適・Kubernetes・Grafana統合Loki
全文検索・アドホック分析・ML異常検知ELK Stack(またはOpenSearch)
構造化ログ・SIEM・AD認証Graylog

関連外部リソース

他の記事も読む

Let's Build Together

OSS導入、自社だけで悩まない。

ツール選定から構築・運用・AI活用まで、オープンソースラボ運営元のClasslessが伴走します。初回のご相談は無料です。