Lambdaの監視はもっと楽になる!Go言語で作る「統一メトリクス」入門
はじめに
「AWS Lambdaを使っているけど、関数の数が増えてきて監視が大変…」 「CloudWatchでエラーやパフォーマンスを追跡したいけど、どこを見ればいいか分からない…」
Go言語で開発された複数のLambda関数でメトリクス(監視指標)を統一し、バラバラだった監視を劇的に改善した方法を示します。
なぜ「メトリクスの統一」が必要だったのか?
私たちのプロジェクトには14個のLambda関数がありましたが、それぞれが思い思いの方法でメトリクスを記録していました。
これは例えるなら、14人それぞれが違う書式の健康診断書を提出しているような状態です。
// 😵 健康診断書がバラバラな状態…
// Aさんの診断書(forgot-password関数)
metricsClient.RecordMetric("パスワード忘れリクエスト数", 1)
metricsClient.RecordMetric("パスワード忘れ入力エラー", 1)
// Bさんの診断書(change-password関数)
metricsClient.RecordMetric("パスワード変更依頼", 1)
metricsClient.RecordMetric("パスワード変更時のエラー", 1)
// Cさんの診断書(login関数)
metricsClient.RecordMetric("ログイン試行", 1)
metricsClient.RecordMetric("ログイン失敗回数", 1)
これでは、全員の健康状態を正しく比較したり、組織全体の健康トレンドを把握したりできませんよね。 具体的には、以下のような問題が起きていました。
- 分析できない: メトリクスの名前が違うため、CloudWatchで「全関数のエラー数を合計する」といった横断的な分析ができません。
- 保守性が低い: 同じようなコードがあちこちに散らばり(DRY原則に反し)、修正が大変でした。
- 記録漏れが起きる: 新しい関数を作った際に、メトリクスの記録を忘れるというミスが発生していました。
このままでは、サービスの信頼性を保つことはできません。そこで、私たちは**「健康診断書のフォーマットを統一する」**ことを決意しました。
改善のゴール:統一された健康診断フォーマットを作る
目指したのは、誰が提出しても同じ項目が記録される、一貫したフォーマットです。
- 【目標1】統一されたメトリクス名:
RequestCount(リクエスト数)のように、全関数で同じ名前を使います。 - 【目標2】Dimensionで分類: 「どの関数の」「どんな操作が」といった詳細情報を**Dimension(ディメンション)**という「ラベル」で付け足せるようにします。これにより、多角的な分析が可能になります。
- 【目標3】コードの重複排除: メトリクスを記録するコードを1箇所にまとめ、全関数で使い回せるようにします。
- 【目標4】記録の自動化: 開発者が意識しなくても、メトリクスが自動で記録される仕組みを作ります。
具体的な改善ステップ
Step 1: 現状把握(どのくらいバラバラか調査)
まず、どのくらいメトリクスの実装がバラバラになっているかを調査しました。
# プロジェクト内の全Goファイルから、メトリクス記録処理を探す
find . -name "*.go" -exec grep -l "RecordMetric" {} \;
結果、45箇所以上で手動のメトリクス記録があり、多くのコードが重複していることが分かりました。
Step 2: 「メトリクス記録機能付き」共通ハンドラーの導入
この改善のキモとなるのが、**メトリクス記録を自動で行う共通部品(ハンドラー)**を作ることです。
改善前(Before): 各関数が、メトリクス機能のない標準ハンドラーをバラバラに使っていました。
func main() {
// 😵 メトリクス記録機能のない、ただのラッパー
wrappedHandler := commonHandler.WrapHandler(businessHandler)
lambda.Start(wrappedHandler)
}
改善後(After):
メトリクス記録を自動で行う、新しい共通ハンドラー WrapHandlerWithMetrics を導入しました。
func main() {
// 🎉 自動でメトリクスを記録してくれる、賢いラッパー
wrappedHandler := commonHandler.WrapHandlerWithMetrics(
businessHandler,
"function-name", // どの関数のメトリクスか
"action_type" // どんな操作のメトリクスか
)
lambda.Start(wrappedHandler)
}
これにより、各Lambda関数はビジネスロジックに集中でき、メトリクス記録という面倒な作業から解放されました。
Step 3: 共通ハンドラー内部でのメトリクス記録処理
新しく作った共通ハンドラーの内部では、以下のような統一されたメトリクスを記録するようにしました。
// 統一されたメトリクス記録処理のイメージ
func (h *CommonHandlerWrapper) recordMetrics(ctx context.Context, /*...引数...*/) {
// Dimensionとは、メトリクスに付ける「ラベル」のこと。
// 「どの関数が」「どの操作で」といった情報を追加できる。
dimensions := []middleware.Dimension{
{Name: "FunctionName", Value: functionName}, // ラベル名: FunctionName, 値: register
{Name: "Action", Value: action}, // ラベル名: Action, 値: registration
}
// 1. リクエスト数(RequestCount)
// 全てのリクエストをこの名前で記録
metricsClient.RecordMetric("RequestCount", 1, "Count", dimensions)
// 2. レスポンス時間(ResponseTime)
metricsClient.RecordMetric("ResponseTime", float64(duration.Milliseconds()), "Milliseconds", dimensions)
// 3. 処理結果(OperationResult)
// 成功か失敗かを "Result" ラベルで分類
resultDimensions := append(dimensions, middleware.Dimension{Name: "Result", Value: "success or failure"})
metricsClient.RecordMetric("OperationResult", 1, "Count", resultDimensions)
// 4. エラー数(ErrorCount)
// エラーが発生した場合のみ記録
if statusCode >= 400 {
metricsClient.RecordMetric("ErrorCount", 1, "Count", dimensions)
}
}
改善の結果:監視がこんなに楽になった!
1. CloudWatchで全体像が一目瞭然に
改善前: 関数ごとにメトリクス名が違い、比較できませんでした。
forgot_password_requests, change_password_requests, login_attempts…
改善後: RequestCount という一つのメトリクス名で、全関数のリクエスト数を比較・合計できるようになりました。
(画像はイメージです)
Dimension というラベルを使えば、
RequestCount+{FunctionName: "login"}→ login関数のリクエスト数RequestCount+{FunctionName: "register"}→ register関数のリクエスト数
といった絞り込みも自由自在です。
2. 開発効率が大幅アップ
| 項目 | Before | After | 改善効果 |
|---|---|---|---|
| メトリクス記録のコード | 45箇所以上 | 1箇所 | 98%削減 |
| メトリクス名の種類 | 20種類以上 | 5種類 | 75%削減 |
| 記録漏れのリスク | 高い | ゼロ | 100%解消 |
開発者はメトリクスのことを気にせず、新しい機能の開発に集中できるようになりました。
3. 効果的なアラートが設定可能に
統一されたメトリクスを使えば、質の高いアラートを簡単に設定できます。
- 「いずれかの関数で、サーバーエラー(5xx系)が5分間に10回以上発生したら通知」
- 「ユーザー情報取得関数の平均レスポンス時間が1秒を超えたら通知」
これにより、問題の早期発見が可能になります。
まとめ:小さな改善が大きな成果を生む
今回のメトリクス統一化によって、私たちは以下の成果を得ることができました。
- 監視品質の向上: 全サービスの状況を正確に、リアルタイムで把握できるようになった。
- 開発効率の向上: 面倒な作業を自動化し、開発者はビジネス価値の創出に集中できるようになった。
- 運用負荷の軽減: 人的ミスがなくなり、安定したサービス運用が可能になった。
「監視の整備は後回しでいいや」と思いがちですが、実はサービスの成長を支える非常に重要な土台です。今回紹介した共通ハンドラーパターンは、どんなプロジェクトでも応用できる強力な手法です。

