CloudWatch Logsにカスタムメトリクスを埋め込める、Embedded Metricsが追加されました!

85件のシェア(ちょっぴり話題の記事)

オペレーション部 江口です。

CloudWatch Logsが、カスタムメトリクスを埋め込んで送ることができるフォーマット"Embedded Metrics Format"に対応しました。

https://aws.amazon.com/jp/about-aws/whats-new/2019/11/amazon-cloudwatch-launches-embedded-metric-format/

ログにこのフォーマットで情報を送ることで、カスタムメトリクスとしてCloudWatchで集計してくれるようになります。

これまでもCLIやAPIでカスタムメトリクスをPushすることは可能でしたし、CloudWatch Logsでフィルターを作成してマッチした文字列の数を数えるメトリクスを作成することはできました。ですが、アプリケーションでカスタムメトリクスを出力したいのであれば、そのためにPushするためのAPIを呼び出さなければいけなかったところ、今回追加されたEmbedded Metrics Formatであればログに出力すればカスタムメトリクスとして認識してくれるので、こうした処理の記述が簡潔になると思います。特にLambdaの処理内でメトリクスを記録させたい場合などは嬉しいのではないでしょうか。

また、情報がCloudWatch Logsにログとして保存されるので、気になったメトリクスがあった場合に、同時間帯の他のメトリクスの値はどうなっていたか、周辺に他にどのようなログがあったか、といった情報をCloudWatch Logsを利用して確認することができる、という点もメリットだと思います。

というわけで実際に自分で使ってみましたので、以後そのレポートです。

フォーマット

フォーマットの詳しい仕様は下記の公式ドキュメントにまとまっています。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Specification.html

上記ページで挙げられているJSONフォーマットの例は下記のようなものです。

{
  "_aws": {
    "Timestamp": 1574109732004,
    "CloudWatchMetrics": [
      {
        "Namespace": "lambda-function-metrics",
        "Dimensions": [["functionVersion"]],
        "Metrics": [
          {
            "Name": "time",
            "Unit": "Milliseconds"
          }
        ]
      }
    ]
  },
  "functionVersion": "$LATEST",
  "time": 100,
  "requestId": "989ffbf8-9ace-4817-a57c-e4dd734019ee"
}

"_aws"下に記述された定義はMetadata Objectで、タイムスタンプ(Timestamp)とメトリクスの定義の情報(CloudWatchMetrics)があります。メトリクスの定義には、

  • 名前空間(Namespace)
  • ディメンション(Dimensions)
  • 実際に記録するメトリクスの名前(Name)と単位(Unit)

といった情報を記述します。

実際のメトリクスとその値はMetaData Objectの後に配置されています。上記例の場合、"time": 100が該当します。

ライブラリ

いまのところPythonとNode.jsのみですが、上記のフォーマットに従ってJSONを生成してくれるクライアントライブラリがAWSのGithubで公開されています。

https://github.com/awslabs/aws-embedded-metrics-python

https://github.com/awslabs/aws-embedded-metrics-node

このライブラリにはEC2/Lambdaでの実行用のサンプルも含まれています(examples/)。

Lambdaで試してみる

とりあえず私はPythonのライブラリのLambdaサンプルを使って、Embedded Metricsを試してみることにしました。 Lambdaのサンプルの場合、デプロイ先となるLambda関数を用意した後、開発用PCからサンプルコードとライブラリを固めたzipをアップロードします。このデプロイ用のスクリプト(deploy.sh)もサンプルコードに同梱されています。

サンプルコード

まずはサンプルコードを見てみましょう。

from aws_embedded_metrics import metric_scope


@metric_scope
def my_handler(event, context, metrics):
    metrics.put_dimensions({"Foo": "Bar"})
    metrics.put_metric("ProcessingLatency", 100, "Milliseconds")
    metrics.set_property("AccountId", "123456789012")
    metrics.set_property("RequestId", "422b1569-16f6-4a03-b8f0-fe3fd9b100f8")
    metrics.set_property("DeviceId", "61270781-c6ac-46f1-baf7-22c808af8162")
    metrics.set_property(
        "Payload", {"sampleTime": 123456789, "temperature": 273.0, "pressure": 101.3}
    )

    return {"message": "Hello!"}

READMEによると、まずメトリクスのログを出力する関数にはデコレータ@metric_scopeを付けます。 該当のコードを読んだかぎり、このデコレータを付けた上で関数のパラメータにmetricsを追加しておくと、メトリクス出力用のLoggerオブジェクトがmetricsに代入されるようです(なので上記コードでもmetricsがパラメータを追加しています)。

metrics.put_dimensionsでディメンションの指定、metrics.put_metricでメトリクス、値、単位を指定しています。このサンプルでは、メトリクス名ProcessingLatencyに、単位Millisecondsで値として100を入れています。

set_propertyは「メトリクスとしては認識させないが付加情報としてログに記録しておく」情報のようです。ここではダミーのAccountIDはRequestID、DeviceID、Payloadといった情報を付加しています。

デプロイ

それでは上記のサンプルコードをLambdaにデプロイしましょう。流れは以下の通りです。

  • デプロイするLambda関数を(空の状態で)作成します。この際、ARN情報を後で利用するためメモしておきます。

  • Github上のライブラリを自分のPCにクローンします。

$ github clone https://github.com/awslabs/aws-embedded-metrics-python.git
  • Lambdaのサンプルコードのディレクトリに移動します。
$ cd aws-embedded-metrics-python/examples/lambda/
  • ディレクトリ内にあるdeploy.shを実行します。./deploy.sh <ARN>> <REGION>という形で、ARNとリージョンを引数として指定します。実行すると、ライブラリとサンプルコード(function.py)をzipに固めてアップロードします。関数名を「EmbeddedMetricsTest」とした場合、実行例は下記のようになります。
$ ./deploy.sh arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:EmbeddedMetricsTest ap-northeast-1
  • アップロードが完了したら、lambda側でハンドラの設定を変更しておきます。サンプルコードそのままであれば、ハンドラはfunction.my_handlerとなります。

  • テストでLambda関数を実行します。

正常に実行が成功すると、下記のようにコンソール上でもログが出力されたことが分かります。

結果

まずはCloudWatch logsを見てみましょう。想定どおり、サンプルのLambda関数で出力されたログを確認できました。

出力されているJSONの情報を前掲のサンプルコードと比べて、どの値がどこに入っているか確認してみるとライブラリについての理解が深まるかもしれません。

メトリクスの情報をみてみると、ディメンジョン「Foo」の値として「Bar」(metrics.put_dimensionsで指定した情報)が入ったメトリクス「ProcessingLatency」が作られ、指定した値「100」がグラフにプロットされていました。うまくEmbedded Metricsが認識されたようです!

終わりに

というわけで簡単ですがEmbedded Metrics Formatで出力したログをCloudWatch logsに送り、カスタムメトリクスとして記録する一連の流れを試してみました。カスタムメトリクスを柔軟に作成する選択肢が増えたことで、CloudWatchでのメトリクスの収集・監視がよりしやすくなるかなと思います。みなさんもぜひ試してみてはいかがでしょうか。

以上、CloudWatch Logsの新機能、Embedded Metricsのご紹介でした。