golang-samber-slog について
標準の slog.Handler インターフェースで構造化ログパイプラインを構築する samber/slog の Go パッケージを扱うスキルです。ハンドラーの合成、サンプリング、属性整形、HTTP ミドルウェア、バックエンドを説明します。
主な機能
- 01合成可能な slog ハンドラー
- 02ルーティング、ファンアウト、フェイルオーバー、プール
- 03ログ量を制御するサンプリング戦略
- 04属性整形と PII マスキング
- 05HTTP ミドルウェアとバックエンド
活用シーン
- 01エラーログを指定したハンドラーへ振り分け
- 02サンプリングによる反復ログの削減
- 03出力前の機密属性の除去
- 04HTTP ログへのリクエスト情報の追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ samber/ cc-skills-golang --skill golang-samber-slogインストール後、Claude Code で/golang-samber-slogを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/backend-handlers.mdhttp-middlewares.mdpipeline-patterns.mdsampling-strategies.md詳細
Persona: Go ロギングアーキテクトです。すべてのレコードが適切なハンドラーを通るログパイプラインを設計します。サンプリングで早い段階にノイズを除去し、レコードがプロセスから出る前にフォーマッターで PII を取り除き、ルーターでエラーを Sentry に、情報ログを Loki に送ります。
samber/slog-**** — Go 向け構造化ログパイプライン
Go 1.21 以降向けの、合成可能な slog.Handler パッケージが 20 種類以上あります。3 つのコアパイプラインライブラリに加え、すべて標準の slog.Handler インターフェースを実装する HTTP ミドルウェアとバックエンドシンクを提供します。
公式リソース:
- github.com/samber/slog-multi — ハンドラーの合成
- github.com/samber/slog-sampling — スループット制御
- github.com/samber/slog-formatter — 属性の変換
このスキルは網羅的ではありません。詳しくはライブラリのドキュメントとコード例を参照してください。
- Go パッケージのドキュメント、シンボル、バージョン、インポーター、既知の脆弱性については、Context7 よりも優先して
samber/cc-skills-golang@golang-pkg-go-devスキル(godig)を参照してください。 - 独自のコード内でこのライブラリの使い方(定義、呼び出し箇所、診断情報)を確認するには、
samber/cc-skills-golang@golang-goplsスキル(gopls)を参照してください。 - Context7 は、pkg.go.dev でインデックス化されていないドキュメントのフォールバックとして引き続き利用できます。
パイプラインモデル
samber/slog のすべてのパイプラインは、標準的な順序に従います。レコードは左から右へ流れます。最初にサンプリングを配置して早期にレコードを除外し、シンクに到達しないレコードの処理に CPU を浪費しないようにします。
record → [Sampling] → [Pipe: trace/PII] → [Router] → [Sinks]
順序が重要です。フォーマットの前にサンプリングすると CPU を節約できます。ルーティングの前にフォーマットすると、すべてのシンクにクリーンな属性が渡されます。順序を逆にすると、破棄されるレコードにも処理が行われ、無駄が生じます。
コアライブラリ
| ライブラリ | 目的 | 主なコンストラクター |
|---|---|---|
slog-multi | ハンドラーの合成 | Fanout、Router、FirstMatch、Failover、Pool、Pipe |
slog-sampling | スループット制御 | UniformSamplingOption、ThresholdSamplingOption、AbsoluteSamplingOption、CustomSamplingOption |
slog-formatter | 属性の変換 | PIIFormatter、ErrorFormatter、FormatByType[T]、FormatByKey、FlattenFormatterMiddleware |
slog-multi — ハンドラーの合成
6 種類の合成パターンがあり、それぞれ異なるルーティングのニーズに対応します。
| パターン | 動作 | レイテンシへの影響 |
|---|---|---|
Fanout(handlers...) | すべてのハンドラーに順番にブロードキャストします | すべてのハンドラーのレイテンシの合計 |
Router().Add(h, predicate).Handler() | 条件に一致するすべてのハンドラーにルーティングします | 条件に一致するハンドラーの処理時間の合計 |
Router().Add(...).FirstMatch().Handler() | 最初に一致したハンドラーのみにルーティングします | 単一ハンドラーのレイテンシ |
Failover()(handlers...) | 成功するまで順番に試行します | プライマリハンドラーのレイテンシ(正常時) |
Pool()(handlers...) | 負荷分散し、各レコードを 1 つのハンドラーに送信します | 単一ハンドラーのレイテンシ |
Pipe(middlewares...).Handler(sink) | シンクの前にミドルウェアチェーンを実行します | ミドルウェアのオーバーヘッド + シンク |
// Route errors to Sentry, all logs to stdout
logger := slog.New(
slogmulti.Router().
Add(sentryHandler, slogmulti.LevelIs(slog.LevelError)).
Add(slog.NewJSONHandler(os.Stdout, nil)).
Handler(),
)
組み込みの述語:LevelIs、LevelIsNot、MessageIs、MessageIsNot、MessageContains、MessageNotContains、AttrValueIs、AttrKindIs。
各パターンの完全なコード例については、パイプラインパターンを参照してください。
slog-sampling — スループット制御
| 戦略 | 動作 | 最適な用途 |
|---|---|---|
| Uniform | すべてのレコードを一定の割合で破棄します | 開発環境/ステージング環境のノイズ低減 |
| Threshold | 各間隔で最初の N 件を記録し、その後は割合 R でサンプリングします | 本番環境 — 初期の可視性を維持します |
| Absolute | 全体で各間隔あたり N 件のレコードに制限します | 厳格なコスト管理 |
| Custom | ユーザー関数が各レコードのサンプリング率を返します | レベルや時間に応じたルール |
サンプリングはパイプラインで最も外側のハンドラーに MUST 配置します。フォーマット後に配置すると、破棄されるレコードにも CPU を無駄に使います。
// Threshold: log first 10 per 5s, then 10% — errors always pass through via Router
logger := slog.New(
slogmulti.
Pipe(slogsampling.ThresholdSamplingOption{
Tick: 5 * time.Second, Threshold: 10, Rate: 0.1,
}.NewMiddleware()).
Handler(innerHandler),
)
マッチャーは、重複排除のために類似したレコードをグループ化します。MatchByLevel()、MatchByMessage()、MatchByLevelAndMessage()(デフォルト)、MatchBySource()、MatchByAttribute(groups, key) を使用できます。
戦略の比較と設定の詳細については、サンプリング戦略を参照してください。
slog-formatter — 属性の変換
Pipe ミドルウェアとして適用すると、すべての後続ハンドラーがクリーンな属性を受け取ります。
logger := slog.New(
slogmulti.Pipe(slogformatter.NewFormatterMiddleware(
slogformatter.PIIFormatter("user"), // mask PII fields
slogformatter.ErrorFormatter("error"), // structured error info
slogformatter.IPAddressFormatter("client"), // mask IP addresses
)).Handler(slog.NewJSONHandler(os.Stdout, nil)),
)
主なフォーマッター:PIIFormatter、ErrorFormatter、TimeFormatter、UnixTimestampFormatter、IPAddressFormatter、HTTPRequestFormatter、HTTPResponseFormatter。汎用フォーマッター:FormatByType[T]、FormatByKey、FormatByKind、FormatByGroup、FormatByGroupKey。FlattenFormatterMiddleware でネストされた属性をフラット化できます。
HTTP ミドルウェア
各フレームワークで一貫したパターンを使用します:router.Use(slogXXX.New(logger))。
利用可能なもの:slog-gin、slog-echo、slog-fiber、slog-chi、slog-http(net/http)。
いずれも、DefaultLevel、ClientErrorLevel、ServerErrorLevel、WithRequestBody、WithResponseBody、WithUserAgent、WithRequestID、WithTraceID、WithSpanID、Filters を含む Config 構造体を共有します。
// Gin with filters — skip health checks
router.Use(sloggin.NewWithConfig(logger, sloggin.Config{
DefaultLevel: slog.LevelInfo,
ClientErrorLevel: slog.LevelWarn,
ServerErrorLevel: slog.LevelError,
WithRequestBody: true,
Filters: []sloggin.Filter{
sloggin.IgnorePath("/health", "/metrics"),
},
}))
フレームワーク固有の設定については、HTTP ミドルウェアを参照してください。
バックエンドシンク
いずれも Option{}.NewXxxHandler() コンストラクターパターンに従います。
| カテゴリー | パッケージ |
|---|---|
| クラウド | slog-datadog、slog-sentry、slog-loki、slog-graylog |
| メッセージング | slog-kafka、slog-fluentd、slog-logstash、slog-nats |
| 通知 | slog-slack、slog-telegram、slog-webhook |
| ストレージ | slog-parquet |
| ブリッジ | slog-zap、slog-zerolog、slog-logrus |
バッチハンドラーでは正常なシャットダウンが必要です — slog-datadog、slog-loki、slog-kafka、slog-parquet はレコードを内部でバッファリングします。シャットダウン時にフラッシュしてください(例:Datadog では handler.Stop(ctx)、Loki では lokiClient.Stop()、Kafka では writer.Close())。そうしないと、バッファー内のログが失われます。
設定例とシャットダウンのパターンについては、バックエンドハンドラーを参照してください。
よくある間違い
| 間違い | 問題が起きる理由 | 修正方法 |
|---|---|---|
| フォーマット後にサンプリングする | 破棄されるレコードのフォーマットにも CPU を無駄に使います | サンプリングを最も外側のハンドラーに配置します |
| 多数の同期ハンドラーにファンアウトする | 呼び出し元がブロックされ、遅延はすべてのハンドラーの合計になります | 並行ディスパッチには Pool() を使用します |
| バッチハンドラーでシャットダウン時のフラッシュがない | シャットダウン時にバッファー内のログが失われます | defer handler.Stop(ctx)(Datadog)、defer lokiClient.Stop()(Loki)、defer writer.Close()(Kafka)を指定します |
| デフォルト/キャッチオールハンドラーがないルーター | 一致しないレコードが通知なく破棄されます | 述語を指定しないハンドラーをキャッチオールとして追加します |
HTTP ミドルウェアなしで AttrFromContext を使用する | コンテキストに抽出対象のリクエスト属性がありません | 先に slog-gin/echo/fiber/chi ミドルウェアをインストールします |
ミドルウェアなしで Pipe を使用する | レコードごとのオーバーヘッドが加わるだけで、何も行いません | ミドルウェアが不要なら Pipe() を削除します |
パフォーマンスに関する警告
- Fanout のレイテンシ = すべてのハンドラーのレイテンシの合計(逐次処理)。10ms のハンドラーが 5 つある場合、ログ呼び出しごとに 50ms かかります。
Pool()を使うと、最大のレイテンシまで短縮できます - Pipe ミドルウェアはレコードごとに関数呼び出しのオーバーヘッドを追加します。チェーンは短く保ってください(ミドルウェア 2~4 個)
- slog-formatterは属性を逐次処理するため、フォーマッターが多いと負荷が累積します。ホットパスで属性をフォーマットする場合は、代わりに型に
slog.LogValuerを実装することをおすすめします - 本番環境にデプロイする前に、
go test -benchでパイプラインをベンチマークしてください
診断: パイプラインのレコードごとの割り当てとレイテンシを測定し、チェーン内で最も多く割り当てを行うハンドラーを特定してください。
ベストプラクティス
- 最初にサンプリングし、次にフォーマットし、最後にルーティングする — この標準的な順序により、無駄な処理を最小限に抑え、すべてのシンクにクリーンなデータが渡るようにします
- 横断的な関心事には Pipe を使う — トレース ID の注入や PII のスクラブは、ハンドラーごとのロジックではなくミドルウェアに実装します
slogmulti.NewHandleInlineHandlerでパイプラインをテストする — 実際のシンクを使わずに、各段階に届くレコードを検証しますAttrFromContextを使うと、HTTP ミドルウェアからリクエストスコープの属性をすべてのハンドラーに伝播できます- ハンドラーごとに異なるレコード群が必要な場合は、Fanout より Router をおすすめします。Router は述語を評価し、一致しないハンドラーをスキップします
関連項目
- → slog の基本(レベル、コンテキスト、ハンドラーの設定、移行)については、
samber/cc-skills-golang@golang-observabilityスキルを参照してください - → ログに記録するか返すかのルールについては、
samber/cc-skills-golang@golang-error-handlingスキルを参照してください - → ログにおける PII の取り扱いについては、
samber/cc-skills-golang@golang-securityスキルを参照してください - →
samber/oopsを使った構造化エラーコンテキストについては、samber/cc-skills-golang@golang-samber-oopsスキルを参照してください
samber/slog-* パッケージでバグや予期しない動作を見つけた場合は、該当するリポジトリ(例:slog-multi/issues、slog-sampling/issues)で issue を作成してください。