先日より、Flywayを使ってRDSのデータベースマイグレーションをLambda関数を使って実装できないかやってみています。前回までの記事は以下を参照。
- AWS Lambda関数をJavaで実装する(1) - miyohide's blog
- AWS Lambda関数をJavaで実装する(2)LambdaからRDSへ接続する - miyohide's blog
- AWS Lambda関数をJavaで実装する(3)CodeBuildを使ってLambdaアプリをデプロイする - miyohide's blog
- AWS Lambda関数をJavaで実装する(4)CodeBuildを使ってLambdaアプリをデプロイする(完全版) - miyohide's blog
今回はPowertools for AWS Lambdaを使ってみます。
Powertools for AWS Lambdaとは
Powertools for AWS LambdaとはLambda向けのユーティリティースイートでトレース、構造化ロギング、カスタムメトリックスができるとのこと。Java、Python、TypeScript、.NETがあります。
以下はJavaの公式ページ。
使ってみる
本ブログの執筆時点である2023年10月時点でのバージョンv1.17.0ではJava 16までしか対応しておらず、Java 17は対応していませんでした。具体的にはJava 17でコンパイルしようとするとコンパイルエラーとなりました。そのため、アプリやLambdaのランタイムのバージョンを落として実装します。
一番お手軽そうなLoggingを試してみます。マニュアルは以下の通り。
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には他にも色々と便利なものがありそうなのでおいおい試してみようかなと。