記事をどれだけ読んだかを示します

Logler: 正直なベンチマーク

この記事の数値は全て実際のベンチマーク実行から得たものだ。シミュレーションデータも、grepを遅く見せるための係数操作も、偽のマルチツール比較もない。ベンチマークスイートはloglerの公開APIだけを使う — search()follow_thread()smart_sample()など。公開インターフェースでテストできないものは「足りないもの」セクションにリストしている。

環境: Python 3.12.11 | logler 1.2.1 | Rustバックエンド | Linux x86_64 (8コア)

実行方法: uv run python -m benchmarks run --scale small

チャートの読み方: 実線は中央値 — 全イテレーションの真ん中の値で、外れ値に強い。網掛け部分はp95(95パーセンタイル)まで — 95%の実行がこの範囲内で完了。狭い帯は予測可能なパフォーマンス、広い帯はGCポーズやキャッシュミスによる時折の遅延を意味する。棒グラフでは各棒の上のひげがp95上限。キャパシティプランニングでは通常負荷に中央値、最悪ケースにp95を使うこと。


検索スケーリング

検索スケーリング

エントリ数を増やしながらの search(files, level="ERROR"):

エントリ数中央値スループット
1,0005.1ms195K/s
10,00019.6ms510K/s
50,000543ms92K/s

スループットは10Kエントリでピーク。50Kではシリアライゼーションコストが支配的に — RustがJSON文字列を返し、Pythonがdictにデシリアライズする。


レベル別検索

レベル別検索

50Kエントリをログレベルでフィルタ:

レベル中央値マッチエントリ数
ERROR587ms~12,500
WARN1.21s~25,000
INFO3.77s~50,000

コストはフィルタの複雑さではなく結果セットサイズに比例。全てにマッチするINFOフィルタは、25%にマッチするERRORフィルタの6倍遅い。


出力フォーマット比較

出力フォーマット

50Kエントリでの4つの出力フォーマット:

フォーマット中央値レスポンスサイズ
full641ms513,019バイト
summary624ms
count591ms202バイト
compact617ms

countフォーマットは202バイト vs full出力の513,019バイト2,540倍のトークン節約。トークンバジェット内で動くLLMエージェントには、これが使えるか使えないかの差になる。


複合フィルタ

複合フィルタ

レベル + クエリパターンフィルタのスケーリング:

エントリ数中央値スループット
1,0001.0ms966K/s
10,0004.5ms2.2M/s
50,00078ms641K/s

複合フィルタはレベル単独よりも劇的に速い。マッチ結果が少ない = JSONシリアライゼーションもPythonデシリアライゼーションも少ない。


階層構築

階層構築

エントリ数別の follow_thread_hierarchy():

エントリ数中央値
1,0006.7ms
10,00067ms
50,000349ms

v1ベンチマークでO(n^2)のボトルネックが発覚した後、246倍の改善が実現した場所。元の実装は親ノードごとに全スレッド/スパンIDをスキャンして命名パターンで子を探していた。50Kエントリでは86秒かかっていた。線形スキャンをBTreeSetプレフィックスインデックスに置き換えて349msに。詳細は最適化の全貌で。


エラーフロー分析

エラーフロー分析

3つの階層サイズでの analyze_error_flow():

サイズ中央値
small0.16ms
medium0.81ms
large1.68ms

完全なエラー伝播ツリーで2ms未満。既に構築された階層をトラバースするため、エントリ数ではなくツリーの深さに制約される。


スレッド追跡スケーリング

スレッド追跡スケーリング

エントリ数別の follow_thread():

エントリ数中央値スループット
1,0000.38ms2.6M/s
10,00012.2ms820K/s
50,000148ms338K/s

1Kエントリでは0.38msで返る — インタラクティブ利用に十分な速度。キャッシュ済みインベスティゲーターにより、同じファイルへの繰り返し呼び出しは再パースコストゼロ。


クロスサービスタイムライン

クロスサービスタイムライン

複数サービスのログファイル間でエントリを相関する cross_service_timeline():

サービス数中央値
27.6ms
36.3ms
511.5ms

5サービスで13ms未満。これがloglerの真骨頂 — ログを中央システムに送ることなく、サービス境界を越えた構造化相関を実現。


スマートサンプリング

サンプリング戦略

50Kエントリでの3つのサンプリング戦略:

戦略中央値
errors_focused8,303ms
diverse8,501ms
chronological7,243ms

スイート内で最も高コストな操作。時間の大部分はRust検索 — サンプリングアルゴリズム自体は高速。最適化記事で何を改善したか解説。


スマートサンプルスケーリング

サンプルスケーリング

エントリ数別の smart_sample():

エントリ数中央値スループット
1,00040ms25K/s
10,000196ms51K/s
50,0006,333ms7.9K/s

10K→50Kの急増はRust検索時間が支配的で、エントリ数に対して超線形にスケールするため。


トークン節約

固定クエリサイズでの出力フォーマット比較:

  • full: 513,019バイト
  • count: 202バイト
  • 節約率: 2,540倍

足りないもの(正直に)

loglerの公開APIで今日ベンチマークできないもの:

  1. 大規模ファイルインデックス — 1GB以上のファイルパースとインデックス構築は未計測
  2. 永続インデックス — 永続インデックスが存在しないためコールドスタートvs温暖スタートの比較不可
  3. Rust vs Python比較 — Rustバックエンド vs 純Pythonフォールバックの直接比較にはRust拡張なしの実行が必要
  4. 同時アクセス — マルチスレッド調査セッションのパフォーマンス未計測
  5. 実世界ログフォーマット — 決定論的合成データを使用。実際のsyslog/logfmtパースのオーバーヘッドは異なる可能性
  6. メモリプロファイリング — 操作ごとのピークメモリ使用量は未追跡

これらは隠された欠陥ではなく、認識されたギャップ。


自分で実行する

# ベンチマーク依存関係をインストール
uv sync --all-groups

# 全14シナリオをリスト
uv run python -m benchmarks list

# smallスケールで実行(~6分)
uv run python -m benchmarks run --scale small

# 特定スイートを実行
uv run python -m benchmarks run --suite hierarchy --scale small

# 最新結果からチャート生成
uv run python -m benchmarks plot

# 2つの実行を比較
uv run python -m benchmarks compare -b results/v1.json -c results/v2.json

結果は再現可能。この記事の全チャートは uv run python -m benchmarks plot が生成する同じJSON出力から作られている。