aws-sdk-go を使用するときの注意点

こんにちは、河野です。

これはTECHSCORE Advent Calendar 2017 の 25日目の記事です。

最近、Go言語用のAWS SDKであるaws-sdk-goを使用して、CloudWatch Logsのログイベントをダウンロードするツールを作りました。aws-sdk-goを本格的に使ってみるのは初めてだったのですが、いくつか気になったことがあったので、まとめてみました。

awsパッケージに目を通しておく

いろいろと実装を始める前に、まずはgithub.com/aws/aws-sdk-go/awsパッケージに目を通しておいたほうが良いです。このパッケージでは、便利な関数や型が提供されています。

http://docs.aws.amazon.com/sdk-for-go/api/aws/

必須なのが値とポインタの変換用の関数群です。

例えば、

  • func String(v string) *string
  • func StringValue(v *string) string

といった基本データ型、Slice、Mapに対応した関数が用意されています。

以下のサンプルコードを見ると、雰囲気がつかめると思います。

また、ミリ秒を扱うための関数もあります。

  • func MillisecondsTimeValue(v *int64) time.Time
  • func TimeUnixMilli(t time.Time) int64

時刻を扱う構造体のtime.TimeとUnix時間(ミリ秒)を変換するための関数になります。

構造体のフィールドでポインタ型が多用されている

aws-sdk-goでは、利用したいAPIのメソッドごとにRequest,Response用の構造体が用意されています。全てのメソッドではないと思いますが、そのようなルールがあるようです。
例えばcloudwatchlogs.FilterLogEventsは以下のように定義されています。

func (c *CloudWatchLogs) FilterLogEvents(input *FilterLogEventsInput) (*FilterLogEventsOutput, error)

Requestの情報として*FilterLogEventsInputが必要で、Responseとして*FilterLogEventsOutputを受け取れるようになっています。
それぞれの構造体は以下のように定義されています(フィールドのタグは除外しています)。

ここで気になるのはフィールドの型です。*int64*string[]*stringというような基本データ型のポインタとして扱うフィールドばかりです。

ポインタから実体を参照する場合には、panicが起きる可能性があるため、直接デリファレンスすることは避けたほうが良いです。そのため、フィールドのデータを取り扱う際には、 aws.Stringaws.StringValueなどの変換関数が必須となります。

例えばログに出力したい場合でも、変換関数を使用したほうが良いです。

Setterを使用する

構造体に値を設定する場合、Setterを使用することもできます。

Setterは、

  • 基本データ型を受け取ってポインタ型にして設定する
  • 構造体自身を返す

という特徴があります。
以下のように、メソッドチェインで記述することが可能です。

ただ、Goでは個別のフィールドのためのSetterは見かけないので違和感があります。構造体リテラルを使用して書くとすると、以下のようになってしまいますし、微妙なところですね。

時刻の扱いはミリ秒単位

cloudwatchlogsのパッケージ内では、時刻の扱いはミリ秒単位で行われています。変換用の関数も提供されていますし、おそらく全体的にそうなんだと思います。

一方、標準のtimeパッケージでは、Unix時間は秒とナノ秒で扱うようになっています。time.Time と int64の変換関数もありますがあくまで秒が単位なので、そのままaws-sdk-goの上で扱おうとすると意図しない時刻になってしまいます。

必ず、

  • func MillisecondsTimeValue(v *int64) time.Time
  • func TimeUnixMilli(t time.Time) int64

を経由するようにしましょう。

先程から何度も例に出していますが、cloudwatchlogs.FilterLogEventsで時刻を指定してログイベントを取得したい場合には、FilterLogEventsInputStartTimeEndTimeを指定します。ここでも変換関数を利用します。

取得したログイベントを扱う構造体のFilteredLogEventはこのようになっています。Timestampはミリ秒なので、こちらも変換が必要になってきます。

例えば時刻とメッセージを表示するには以下のようになります。

まとめ

aws-sdk-goを使う際の注意点をまとめます。

  • awsパッケージに用意されている変換関数を把握しておく
  • ポインタからのデリファレンスを安全に行うため、aws.XXXXValueを使用する
  • 構造体に用意されているSetterを使用すると、値からポインタの変換を気にしなくて良い
  • 時刻の単位はミリ秒なので、専用の関数を使用する

私はこの辺りをわかっていなかったので、1日ほど時間をムダにした気がします。

aws-sdk-goはAWSのサービスが大きい分、ライブラリも大きいです。まだ使っていないサービスもあるので、他にもハマるポイントが有るのかもしれませんね。
気になることがあったらパッケージのリファレンスを参照するように気をつけようと思います。

Comments are closed, but you can leave a trackback: Trackback URL.