API Gateway のカスタムアクセスログで EMF を使ってカスタムメトリクスを出力してみた

2023.04.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いわさです。

Amazon API Gateway では任意のフォーマットやログ構造で CloudWatch Logs か Kinesis Firehose へのログ出力をサポートしています。
以前次のような記事でログをカスタマイズする方法を紹介したことがあります。

また、CloudWatch Logs には Embedded Metrics Format という構造でログ出力することで、そのログ内容からカスタムメトリクスを自動生成してくれる機能が備わっています。

EMF を使うには以下の前提条件があります。

手動で作成した埋め込みメトリクスフォーマットログを送信するには、PutLogEvents API または CloudWatch エージェントを使用します。

埋込みメトリクスフォーマットログの手動生成 - Amazon CloudWatch より引用

そこで、API Gateway で EMF でカスタムアクセスログを CloudWatch Logs へ出力したらそのままカスタムメトリクスにすることが出来るのではと思ったので、本日は実際に試してみました。

API Gateway のカスタムアクセスログ

まず API Gateway のカスタムアクセスログがデフォルトでどういうものなのかを確認してみましょう。
次のように適当な REST API を用意しバックエンドにモックを設定します。

デプロイ出来たらステージのログ/トレースタブからカスタムアクセスログを有効化します。
デフォルトでは無効化されておりアクセスログは出力されません。

まずは上位のように新規作成した CloudWatch Logs グループを作成し、ARN を指定し、ログ形式はデフォルトで用意されているサンプルの CLF を使いましょう。

更新後に次のように HTTP リクエストを送信します。

% curl -X GET "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage"
hoge
% curl -X POST "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage"
hoge

出力先に指定したロググループを確認するとログストリームが自動生成されていると思います。

次のような形式でアクセスログが出力されていました。
ここまでが API Gateway 通常のカスタムアクセスログ機能です。

Embedded Metrics Format を設定する

EMF については冒頭の記事のとおりなのでここでは詳しく紹介しませんが、今回は API のリクエスト数をメソッド別に計測してみましょう。
Namespace で適当な名前空間名を指定し、Dimensions は今回は 1 つだけ用意し HTTP メソッドを設定したいと思います。

Unit や StorageResolution などは設定ルールが定められているので気をつけてください。
ここでは単位に Count を指定し、非高解像度メトリクスとしています。

作成してみたのが以下のような形式です。

{
  "_aws": {
    "Timestamp": "$context.requestTimeEpoch",
    "CloudWatchMetrics": [
      {
        "Namespace": "hoge0329namespace1",
        "Dimensions": [["hoge0329dimension"]],
        "Metrics": [
          {
            "Name": "hoge0329metric1",
            "Unit": "Count",
            "StorageResolution": 60
          }
        ]
      }
    ]
  },
  "hoge0329dimension": "$context.httpMethod",
  "hoge0329metric1": 1,
  "requestId": "$context.requestId"
}

これを先程のステージ設定に適用しましょう。

カスタムアクセスログとカスタムメトリクスの確認

ここでは確認のために GET リクエストを 2 回、POST リクエストを 5 回行ってみました。

% curl -X GET "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage" 
hoge
% curl -X GET "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage" 
hoge
% curl -X POST "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage"
hoge
% curl -X POST "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage"
hoge
% curl -X POST "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage"
hoge
% curl -X POST "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage"
hoge
% curl -X POST "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage"
hoge

まずはロググループからカスタムアクセスログが期待どおり出力されているか確認しましょう。
API Gateway のログ出力仕様に則って組み込みの変数などを使っているのでまずはログ出力の確認が重要です。

どうですか。良さそうですね。
続いて CloudWatch のメトリクスメニューを参照してみましょう。

カスタム名前空間に指定した名前空間名で出力されていますね。

詳細を確認してみると GET と POST メソッドをディメンションとするメトリクスが表示されています。
グラフ上で確認してみると、JST の該当時間に GET リクエストが 2 回、POST リクエストが 5 回呼び出されていることが確認出来ますね。

さいごに

本日は API Gateway のカスタムアクセスログで EMF を使ってカスタムメトリクスを出力してみました。
出来ましたね!

特に Lambda など特別な実装をせずにログ設定だけでメトリクスが出力出来ました。
これは結構応用効きそうな気がします。

また、EMF のような構造的なログ出力をしておくと、CloudWatch Logs Insights などを利用する際にもクエリしやすくなります。
CloudWatch Logs に関しては料金面で若干注意は必要ですが、何かしら構造化したログ出力をせねばと考えている方は EMF も検討してみてください。おもしろい機能だと思います。