AWS Lambdaのロギングを考える

ロギングをどうするかで困っていた。AWS Lambdaでは、プリント出力したものがCloudWatchに保存されてとても便利なのだが、考えもなしにとりあえずポンポン入れていたところ、確かに情報はあるので追えないことはないんだが、地道に時間にあたりをつけて検索するなど、非常に泥臭い作業が要求され、なにかとつらかった。

APIのコール回数など集計したいという要件も出てきて、重い腰をあげてロギングについて頑張って考えました、という話。

ユースケースを考える

AWS Lambdaで、何も考えずにとにかく必要そうなのをログ出力しているが、フォーマットも何も整っていないため、ほしい情報を探し当てるのも一苦労だ。

ログをjson形式に構造化させてやると、CloudWatch Insightsでクエリを投げて検索・集計することができる。ということで、ユースケースに対応できるように、ログ出力について考えたい。

ユースケースとして以下を考慮。

  • ERRORだけ抜き出す
  • ユーザー別に叩いたAPIについて集計する
  • 詳細な検索ができるように、ハンドラに渡された情報は全部取っておく

前提条件として、node.jsを使っていたりPythonを使っていたりする。そのため、特定の言語のライブラリに依存した解決はあまり好ましくない

結果

以上の条件を考えて色々調査し、必要なことを考えた結果、以下のような感じになった。

{
  "msg": string // フィルタリングできるような固有のメッセージ
  "funcName": string // 実行関数
  "dateTime": string // ログ出力した時刻 RFC3339 に則る(jsならDateオブジェクトをconsole出力すればよい)
  "level": INFO | WARN | ERROR,
  "event": object // Lambda関数のeventパラメータをそのまま
  "input": object // 必要なやつ
}

levelでログレベルを設定。inputとmsgでフィルタリング、集計を容易に。困ったらeventとfuncNameで頑張って追えるようにしておいた。また、独自フォーマットなので言語やライブラリに依存しない。

このフォーマットはほとんど「AWS Lambda Logging: An Intro How-To and Best Practices | Scalyr」を参考にしています。

以下のような使い方を想定(node.js)。

function logging(msg, funcName, event, level, inputValues) {
  const logMsg = {
    msg: msg,
    funcName: funcName,
    dateTime: new Date(),
    level: level,
    event: event,
    input: inputValues
  }
  if (level === "INFO") {
    console.info(JSON.stringify(logMsg))
  } else if (level === "WARN") {
    console.warn(JSON.stringify(logMsg))
  } else if (level === "ERROR") {
    console.error(JSON.stringify(logMsg))
  } else {
    console.log(JSON.stringify(logMsg))
  }
}

exports.handler = async (event, context, callback) => {
  logging("CallApi", "functions/users/app.handler", event, "INFO", {userId: "testUser"});
}

で、CloudWatch Insightsを使うとたとえば以下のようなクエリを投げて集計できるわけだ。

filter msg like /CallApi/
| stats count(input.userId) by input.userId

運用を通じてブラッシュアップしていきたい。

参考リンク

この記事は、開発中のWebサービスQnQで草稿を作りました。よかったら見ていってね(宣伝)。

Lambda関数のロギング設計を考える | QnQ

その他、参考にさせていただいた記事です。ありがとうございました。

関連記事

スポンサーリンク

カテゴリーaws

コメントを残す

メールアドレスが公開されることはありません。