CloudWatch Logs Insights を使って Mackerel 上にアプリケーションのメトリック監視環境を手早く構築する

この記事は Mackerel Advent Calendar 2021 の 15 日目の記事です. 昨日は id:kazeburo さんの mkr plugin install 時の403 API rate limit exceededエラーを回避する方法 でした.


こんにちは id:susisu です. 普段は Mackerel 開発チームでアプリケーションエンジニアをしています.

先日 mackerelio-labs にて cloudwatch-logs-aggregator という Terraform モジュールをひっそりと公開しました.

github.com

この記事では, このモジュールについてと, これを使って AWS 環境で動作するアプリケーションのメトリックの監視環境を手早く Mackerel 上に構築する方法を紹介します.

アプリケーションのメトリックについて

(ここでアプリケーションとは, 汎用的なシステムやミドルウェアとは区別された, ユーザー独自のプログラムを指すこととします.)

動作しているアプリケーションの様子を把握するためには, アプリケーションの可観測性 (observability) を高めることが重要です. 可観測性を成り立たせるための要素としては, 一般的にはログ・メトリック・トレースの 3 つが挙げられますが, このうちメトリックは, 時系列で傾向を把握したり, 定量的な指標を元にアラートを上げたりするのに最も適しています.

典型的なアプリケーションのメトリックとしては, 以下のようなものが当てはまります.

  • 処理されたデータの数
  • データの処理にかかった速度
  • 発生したエラー数

こういったものはログを用いても簡単な監視を行うことはできますが, 割合のようにより複雑な指標に基づいて監視を行ったり, 時間的な変化を把握したりするためには, やはりメトリックの形が便利です.

アプリケーションからメトリックを出力する

アプリケーションからメトリックを出力して利用するためには, 通常アプリケーションに対してなんらかの計装 (instrumentation) が必要になってきます.

例えば最も単純に, アプリケーションから直接 Mackerel にメトリックを投稿するのであれば,

  • メトリックを記録するための仕組みを作る
  • 定期的に Mackerel の API を呼び出してメトリックを投稿する

といった変更をアプリケーションに対して加えることになるはずです.

一方でこういったメトリック出力のための計装は, ログの出力の場合と比較するといくらか複雑です. メトリックの場合, 記録のためにアプリケーションに状態を持たせたり, 投稿のために API の呼び出しのような実装が必要になりますが, ログであれば状態は必要なく, 出力先も標準出力で良いなど, いくぶん簡単な実装で済むはずです.

CloudWatch Logs にアプリケーションのメトリックを記録する

ここではできるだけ手っ取り早くプリケーションのメトリックを記録したい, ということでログの仕組みを利用してしまいましょう.

まずメトリック (特に counter や histogram と呼ばれるような種類のもの) は, 値を含んだ構造化ログを計測のサンプルごとに出力することとします.

例として, なんらかのバッチ処理で処理されたデータの件数のようなメトリックを記録するのであれば, 処理の実行ごとに一行ずつ以下のようなログの出力が想定されます.

{"level":"info","msg": "data processed","count":42}
{"level":"info","msg": "data processed","count":94}
...

このようにして出力されたログは, CloudWatch Logs へ集約することとします. アプリケーションが AWS 環境, 特に ECS や Lambda などで動作している場合であれば, このための設定は簡単に行えるはずです.

CloudWatch Logs に出力されたログに対しては, Insights のクエリを使って高度な集計や分析を行うことができます. このクエリは上記のようなログを集計してメトリックに変換するのに十分な力を持っています.

ここで特に重要なのが stats コマンドで, これはログに含まれる値を使って, count(), sum(), avg() といった統計的な値を計算することができます. 上のバッチ処理のログの例であれば, 例えば期間中の合計処理件数を以下のようなクエリで求められます.

filter msg = "data processed"
| stats sum(count) as processed_count

あとはこのようなクエリを定期的に実行し, Mackerel にメトリックとして投稿するようにすれば, アプリケーションのメトリックの監視・可視化のための準備が整うはずです.

cloudwatch-logs-aggregator を使ってサービスメトリックを投稿する

ここではじめに紹介した cloudwatch-logs-aggregator の出番です.

cloudwatch-logs-aggregator は 2 つの Terraform モジュールから構成され, それぞれ以下のような役割を持っています.

  • cloudwatch-logs-aggregator/lambda: CloudWatch Logs Insights のクエリを発行し, Mackerel にサービスメトリックを投稿するための Lambda 関数の作成
  • cloudwatch-logs-aggregator/rule: 上記の Lambda 関数を実行するパラメータの設定と, 定期的に実行するための EventBridge (CloudWatch Events) のルールの作成

詳しい利用方法については上記リポジトリの README に譲りますが, これらのモジュールを用いることで, CloudWatch Logs のログからメトリックを生成し, Mackerel にサービスメトリックとして投稿する仕組みを簡単に構築することができます.

# Lambda 関数
module "cw_logs_aggregator_lambda" {
  source = "github.com/mackerelio-labs/mackerel-monitoring-modules//cloudwatch-logs-aggregator/lambda?ref=v0.1.0"

  # ...
}

# EventBridge のルール
module "cw_logs_aggregator_rule_my_batch_job" {
  source = "github.com/mackerelio-labs/mackerel-monitoring-modules//cloudwatch-logs-aggregator/rule?ref=v0.1.0"
  
  function_arn = module.cw_logs_aggregator_lambda.function_arn

  # 指定したクエリを発行し
  query = "filter msg = \"data processed\" | stats sum(count) as processed_count"

  # Mackerel にサービスメトリックとして投稿
  service_name = "my-service"

  # ...
}

これで Mackerel にメトリックが投稿できたら, あとはで監視ルールを設定したり, カスタムダッシュボードを作って可視化するだけです!

cloudwatch-logs-aggregator について

この CloudWatch Logs からメトリックを生成する仕組みは Mackerel 開発チームでも実際の運用に使われており, cloudwatch-logs-aggregator はそれを再利用可能な形にして公開したものです.

上ではアプリケーションのメトリックの監視についての使い方を紹介しましたが, ミドルウェアのログからメトリックを生成したり, チェックプラグインを使ったログ監視の代替といった用途にも利用できるかと思います.

現在 cloudwatch-logs-aggregator はアルファ版という形で公開しています. Mackerel の活用により役に立つ機能を提供できるようブラッシュアップしていきたいと考えていますので, 是非ご試用いただき, リポジトリの Issue や Mackerel ユーザーグループの Slack チャンネル #cloudwatch-logs-aggregator などからフィードバックをいただけるとありがたいです.

利用にあたっては以下の点にご留意ください.

  • 上記の通りアルファ版として提供されます. 仕様は今後のバージョンアップで大きく変更される可能性があります
  • CloudWatch Logs Insights のクエリ発行時に AWS の利用料金が発生します (2021 年 12 月現在, 東京 (ap-northeast1) リージョンでは 1 GB あたり 0.0076 USD)

まとめ

  • cloudwatch-logs-aggregator というモジュールを公開しました
  • これを使って, アプリケーションのメトリックの監視のための準備を手早く行う方法を紹介しました
  • 機能をより良くしていくため, フィードバックを募集しています 🙏