bunyanでAWS Lambdaを使ったAPIのログをCloudWatch Logsでフィルターしやすくする

AWS Lambdaのログ、どのように取得されていますか? Node.jsを使っている場合、一番てっとり早いのはconsole.logで記録することです。 console.logに頼るとつらい点 console.logで […]

広告ここから
広告ここまで

目次

    AWS Lambdaのログ、どのように取得されていますか?

    Node.jsを使っている場合、一番てっとり早いのはconsole.logで記録することです。

    console.logに頼るとつらい点

    console.logでログを取るようにすると、CloudWatch Logsから調べるのが少し厄介です。

    この関数はただ純粋にログを出すだけなので、「何がどれのログか」が拾いにくいという点があります。

    また、JSONがはいるのかstringで入るのかなども特に決まっていないので、実装者によってログのフォーマットが変わるなどの問題もあります。そうなるともうCloudWatch Logsで頑張って目グレップするか、Elasticsearchあたりに投げ込んで思いっきり検索回すかしかないかなと思います。

    bunyanを試している理由

    bunyanはJSON形式でログを取ることができるライブラリです。

    // import
    const bunyan = require('bunyan');
    
    // setup logger
    const log = bunyan.createLogger({name: 'myapp'});
    
    // log
    log.info('hi');

    このように使うと、JSON形式でログがでます。

    {"name":"myapp","hostname":"banana.local","pid":40161,"level":30,"msg":"hi","time":"2013-01-04T18:46:23.851Z","v":0}

    bunyanとCloudWatch Logsは相性が良い。たぶん

    bunyanはJSON形式でログを残します。そしてCloudWatch LogsにはJSONメトリクスフィルターがあります。

    と、いうことはbunyanでログを残すようにすればCloudWatch Logsでフィルターがしやすくなる(はず)です。

    APIバックエンドでのロギング

    複数回同時にAPIへアクセスきた場合、それぞれのログが1つのストリームにまとめて記録されることがあります。

    そうなると、1行ずつどのリクエストのものか確認しないといけなくなり、なかなか大変です。

    そこでbunyanを使う場合は、request idを記録するようにしてやります。

    import { APIGatewayProxyHandler } from 'aws-lambda'
    import * as bunyan from 'bunyan'
    import * as bunyanFormat from 'bunyan-format'
    
    /**
     * Default configuration
     **/
    const defaultOptions: Partial<bunyan.LoggerOptions> = {
      level: 'debug',
      stream: new bunyanFormat({
        outputMode: 'bunyan',
        levelInString: true
      }),
    }
    
    /**
     * Create logger
     **/
    const createBunyanLogger = (opts?: bunyan.LoggerOptions): bunyan => {
      const logger = bunyan.createLogger({
        ...defaultOptions,
        ...opts
      })
      return logger
    }
    
    export const handler: APIGatewayProxyHandler = async (event) => {
      const logger = createBunyanLogger({
        name: 'MyTestAPI',
        requestId: event.requestContext.requestId
      })
      logger.info(event)
      return {
        statusCode: 200,
        body: JSON.stringify({message: 'Hello'})
      }
    }

    上のサンプルでは、requestIdというパラメタをカスタムで追加しています。これはCloudWatch Logsでのメトリクスフィルタを使う際に利用します。

    記録したログを見る

    上記のサンプルのような形でログを取ることで、APIリクエスト毎にメトリクスを見ることができます。

    CloudWatch LogsやRollbarなどでしらべたいリクエストのIDをまず調べます。

    その後、メトリクスフィルタで{$.requestId = "89eb2f4a-a645-4842-a288-65e7de3e28bf"}のようにフィルタすることで、そのリクエストのログだけをまとめて見れるようになります。

    おわりに

    LoggerのセットアップをPJ / API毎にしないといけない手間はありますが、運用のことを考えると充分リターンは大きいかなと思います。

    Nest.jsなどのFWを使っていれば標準のAPIであるかもしれないので、技術選定の際にはこの辺りも考慮してみてもよいかもしれません。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark