AWS Lambda関数をJavaで実装する(5)Powertools for AWS Lambdaを入れてみる

先日より、Flywayを使ってRDSのデータベースマイグレーションをLambda関数を使って実装できないかやってみています。前回までの記事は以下を参照。

今回はPowertools for AWS Lambdaを使ってみます。

Powertools for AWS Lambdaとは

Powertools for AWS LambdaとはLambda向けのユーティリティースイートでトレース、構造化ロギング、カスタムメトリックスができるとのこと。JavaPython、TypeScript、.NETがあります。

以下はJavaの公式ページ。

docs.powertools.aws.dev

使ってみる

本ブログの執筆時点である2023年10月時点でのバージョンv1.17.0ではJava 16までしか対応しておらず、Java 17は対応していませんでした。具体的にはJava 17でコンパイルしようとするとコンパイルエラーとなりました。そのため、アプリやLambdaのランタイムのバージョンを落として実装します。

一番お手軽そうなLoggingを試してみます。マニュアルは以下の通り。

docs.powertools.aws.dev

MavenやGradleに必要なライブラリを追加して、log4j2.xmlを作成しておきます。

ライブラリを入れるだけでは特に何も起きません。Lambda関数のメソッドに対して@Logging(logEvent = true)を付与しておきます。

public class App implements RequestHandler<InputRecord, String> {
  @Override
  @Logging(logEvent = true)  // ←  これを追記
  public String handleRequest(InputRecord input, Context context) {
    // Lambda処理の実装
  }

}

すると、ログにはメソッドの実行情報などが構造化された形で出力されます。

{"timestamp":"2023-10-27T11:47:15.211+0000UTC","instant":{"epochSecond":1698407235,"nanoOfSecond":211010000},"thread":"main","level":"INFO","loggerName":"com.github.miyohide.App","message":"{\"bucketName\":\"xxxxxxxxxxxxxxxxxxxx\"}","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","threadId":1,"threadPriority":5,"coldStart":"true","functionArn":"arn:xxxxxxxxxxxxxxxxxxxxxxxxx","functionMemorySize":"512","functionName":"myLambda1","functionVersion":"$LATEST","function_request_id":"xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx","samplingRate":"0.0","service":"service_undefined","xray_trace_id":"y-yyyyyyyy-yyyyyyyyyyyyyyyyy"}

ただ、以下のようにcontext.getLogger()で得られたLambdaLoggerを使ったログ出力では構造化されていませんでした。

LambdaLogger logger = context.getLogger();
logger.log("Input data = [" + input.toString() + "]");  // 出力は Input data = [InputRecord{bucketName='xxxxxxxxxxxxxxxxxxxx'}] となる

構造化したログ出力には、以下のようにorg.apache.logging.log4j.LogManagerを使ってLoggerインスタンスを作成することで実装します。

public class App implements RequestHandler<InputRecord, String> {
  private final Logger log = LogManager.getLogger(App.class);

  @Override
  @Logging(logEvent = true)
  public String handleRequest(InputRecord input, Context context) {
    log.info("Input data = [" + input.toString() + "]");
    // 以下省略
  }
}

結果として、以下のように構造化されます。

{"timestamp":"2023-10-27T11:53:01.210+0000UTC","instant":{"epochSecond":1698407581,"nanoOfSecond":210934000},"thread":"main","level":"INFO","loggerName":"com.github.miyohide.App","message":"Input data = [InputRecord{bucketName='xxxxxxxxxxxxxxxxxxxx'}]","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","threadId":1,"threadPriority":5,"coldStart":"true","functionArn":"arn:xxxxxxxxxxxxxxxxxxxxxxxxx","functionMemorySize":"512","functionName":"myLambda1","functionVersion":"$LATEST","function_request_id":"xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx","samplingRate":"0.0","service":"service_undefined","xray_trace_id":"y-yyyyyyyy-yyyyyyyyyyyyyyyyy"}

Powertools for AWS Lambdaには他にも色々と便利なものがありそうなのでおいおい試してみようかなと。