はじめに
前回までの記事ではアプリケーションで整形したEMFのログをCloud Watch Agentで送信していました。 この記事にはアプリでEMFにログを整形するのではなく、オープン規格であるOpenTelemetryライブラリを使って独自のメトリクスを送信してみます。
構成
OTEL CollectorとしてAWS Distro for OpenTelemetryを使います。今回はEMFでメトリクスを送信したいのでAWS CloudWatch EMF Exporterを構成します。
アプリ側は以下のpipパッケージを使用します。
opentelemetry-sdk
opentelemetry-exporter-otlp
otel-agent-config.yaml
エージェントの設定は下記の通りです。
metric_declarations
で送信されるメトリクスに付与するDimensionを設定します。
これを設定しないとコレクタ側で付与される余計なメタ情報も追加されてしまいます。
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 60s
exporters:
awsemf:
log_group_name: 'gray-failure-emf'
log_stream_name: '{ContainerInstanceId}'
namespace: 'app'
dimension_rollup_option: 1
log_retention: 60
metric_declarations:
dimensions: # 付与するDimensionの組み合わせ
- ["AvailabilityZone"]
- ["AvailabilityZone", "DockerId"]
metric_name_selectors: #この設定がマッチするメトリクス名
- "^backend.*" #NOTE: メトリクス名は小文字に正規化される
service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch]
exporters: [awsemf]
アプリのソースコード
アプリ側のコードは以下の通りです。
メトリクス送信
メトリクスが観測されるタイミングと送信されるタイミングは一致しない(非同期処理)なので、観測値と共にタイムスタンプを記録しておいて、リーダーによってメトリクスが読み取られる度に送信します。タイムスタンプはtime_unix_nano
という属性として指定します。
# オブザーバーを作成
meter.create_observable_gauge(
"backendlatency", callbacks=[backend_latency_metric_callback],unit='MilliSecond'
)
# アプリで発生したメトリクスの観測値を保存する
backend_latency_metrics.append((time.time_ns(), latency))
# リーダーから呼び出されるコールバック
def backend_latency_metric_callback(options):
observes = []
# 保存していた観測値を変換して送信する
for ts, latency in backend_latency_metrics:
observes.append(metrics.Observation(latency, dict(**{'time_unix_nano': ts}, **metadata())))
backend_latency_metrics.clear()
return observes
docker-compse.yml
今回はメトリクス送信の確認だけなのでdocker composeを使ってローカルで確認します。 以下のように設定ファイルを指定してコレクタを起動します。
version: '3'
services:
otel:
image: amazon/aws-otel-collector:latest
command: ["--config=/etc/otel-agent/otel-agent-config.yaml"]
env_file:
- .env
volumes:
- ./otel-agent:/etc/otel-agent
ports:
- "1777:1777" # pprof extension
- "55679:55679" # zpages extension
- "4317:4317" # OTLP receiver
- "4318:4318" # OTLP receiver
- "13133" # health_check
メトリクスの確認
15分ほど動作させると下記の通り送信したメトリクスを確認できました。
まとめ
EMF Exporterを使うことでアプリ側はOpenTelemetryに従ってメトリクスを送信しながらEMFでCloudWatchにログとメトリクスを送信できました。 非同期の送信処理は少し癖がありますがEMF固有のコードをなくすことができました。