AWS SDK for Go v2 で EMF

はじめに

AWS では、EMF という CloudWatch ログに決まったフォーマットの JSONをパブリッシュするとそれをメトリクスとして扱ってくれる機能がある。 悪名高い AWS SDK for Go v2 で EMF 形式で送信する方法のメモである。

EMF ヘッダを設定する

ドキュメントにある通り、次のヘッダーを付与する必要がある。

x-amzn-logs-format: json/emf

次のように、PutLogEvents の 第 3 引数の optFns で設定できる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import (
	"context"

	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
	smithyhttp "github.com/aws/smithy-go/transport/http"
)

func newCWLClient(ctx context.Context) (*cloudwatchlogs.Client, error) {
	cfg, err := config.LoadDefaultConfig(context.Background())
	if err != nil {
		return nil, err
	}
	client := cloudwatchlogs.NewFromConfig(cfg)
	return client, nil
}

func publishMetric(ctx context.Context, client *cloudwatchlogs.Client, input *cloudwatchlogs.PutLogEventsInput) error {
	_, err := client.PutLogEvents(ctx, input, func(o *cloudwatchlogs.Options) {
		o.APIOptions = append(o.APIOptions, smithyhttp.SetHeaderValue("x-amzn-logs-format", "json/emf"))
	})
	return err
}

JSON を構築する

使ったことはないが、aws-embedded-metrics-golangを使うとチェインメソッドで構築できそう。 Lambda では、デフォルトで x-amzn-logs-format: json/emf が設定されているとのことで、aws-embedded-metrics-golang を使えば、io.Writer に標準出力・エラー(os.Stdout/os.Stderr)を指定すれば簡単に EMF として扱える。

Docker(moby) の v23.0.0 では、awslogs ドライバーで emf を指定できるようになったので、Lambda 同様に標準出力・エラーに吐き出せば簡単に扱えるようになるらしい。ただし、Fargate では Docker を使っていないため、別途 shim logger 側の対応が必要そう。

Add a new option to the awslogs log driver to specify the log format that’s sent to CloudWatch. moby/moby#42838

上記外では、前述の SDK でヘッダーの設定が必要となり、EMF の構造体を定義し json.Marshal したほうがいいかもしれない。