🚨

cwl-linkの紹介

2023/02/14に公開

AWS Lambdaのデバック作業が捗る自作のライブラリーを紹介します。

https://www.npmjs.com/package/cwl-link

cwl-linkの概要

このライブラリーは、Node.jsのAWS Lambda ContextからAWSのCloudWatch Logsのコンソールページに移動できるリンクを生成します。LambdaのリクエストIDでログが絞り込まれている状態でページが開きます。

CloudWatch Logsのダッシュボードからページを潜っていく手間が掛からず、すぐに目的のログが読める。機能は小さいけど、素晴らしい。

NPMのページにすべてのUsageがあるので、ここでは簡単なケースだけ紹介します。

import * as cwllink from 'cwl-link';

exports.handler = function(event, context) {
  // This is a link for a Log Event page filtered by request id.
  const link = cwllink.fromLambdaContext(context);
  ...
}

このlinkの内容は次のようなURLです。

https://{REGION}.console.aws.amazon.com/cloudwatch/home?region={REGION}#logsV2:log-groups/log-group/{LOG_GROUP}/log-events/{LOG_EVENT}$3F$filterPattern$3D$2522{REQUEST_ID}$2522

このリンクをクリックするとLambdaのリクエストIDで絞り込まれている状態のログが読めます!!

SlackやTeamsのWeb hookを使って通知する際に、cwl-linkで生成したリンクを含めればクリック1つでログを読める環境が整います。『すぐ読める』って同じこと3回ぐらい書いてますねw

AWS Lambda Powertools for TypeScripと一緒に使う

Lambdaのエラーログに手軽にアクセスしたいケースで使ってもらいたいですが、
ログ出力には@aws-lambda-powertools/loggerがおすすめです。
https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/logger/

このライブラリーもfunction_request_idとしてリクエストIDをログに含めてくれるのでcwl-linkも一緒に活躍できます。

エラー処理のサンプルもドキュメントにあります。
https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/logger/#logging-errors

サブスクリプションフィルターでタイムアウト発生を通知する

ログを読みたいタイミングはエラーだけではないですね。タイムアウトしてしまった場合もログは気になると思います。メインの処理でcwl-linkを使用していても、タイムアウトしたらその通知が飛ばせません。

そこでタイムアウトの通知にはCloudWatch Logsのサブスクリプションフィルターを使いましょう。

タイムウトでは次のようなメッセージが流れます。

2023-02-13T15:18:03.440Z 8a411f37-434e-400d-94b8-1057212c88ff Task timed out after 3.01 seconds

このログを"Task timed out after"というパターンで拾って通知しましょう。フィルターパターンのドキュメントはこちら

サブスクリプションフィルターでトリガーされたLambdaの詳細な解説は省きますがcwllink.fromLambdaEventTriggeredBySubscriptionFilters(event)
こちらのドキュメントのような処理を実行してリンクを生成してくれます。

タイムアウトを通知するもう1つのアイディア

ちょっと脱線します。
タイムアウトまでの残り時間を教えてくれるcontext.getRemainingTimeInMillis()を上手に活用すれば、いい感じに通知処理を実行できる可能性はあります。そうすると通知処理のためにもう1つLambdaを作る手間が省けます。

メイン処理でasync/awaitを駆使して反復処理をマイクロタスクに分けることでcontext.getRemainingTimeInMillis()を呼び出すタイミングを作ります。タイムアウトギリギリなら通知処理を実行します。

もしこの方法でタイムアウトの通知を実現するなら、タイムアウトギリギリに関数を実行できるライブラリーを開発してcwl-linkと組み合わせる感じですね。async/awaitしつつ反復処理するためのインターフェースを考えて(ジェネレーター関数かな?)、タイムアウトギリギリで呼びたい関数と一緒に渡します。

ライブラリー名はgirigiri-fireにします。時間の掛かる反復処理をジェネレーター関数で定義してgirigiri()に渡せば、タイムアウト直前に処理を実行します。

type GirigiriFireOptions = { thresholdMillis?: number };
type GirigiriFire<T, R> = (
    generatorFn: Generator<T, R>,
    beforeTimeoutFn: (value: T) => void,
    context: Context,
    options?: GirigiriFireOptions
) => R;

うん、次に作るもの決めました。

まとめ

このライブラリーを開発してから10ヶ月ほど業務に導入して使ってみましたが、ログを探す手間が省けて本当に開発体験が良くなったと感じます。是非、試してもらえると嬉しいです。

Discussion