Amazon CloudWatch SyntheticsのCanary実行が「Cannot find module ‘SyntheticsLogHelper’」となり失敗する場合の対処(AWS CDK)

2021.09.17

こんにちは、CX事業本部 IoT事業部の若槻です。

Amazon CloudWatch Syntheticsを使用すると、WebサイトやAPIのURLの監視(外形監視)を行うことができます。

今回は、AWS CDKで実装したCanaryの実行が「Cannot find module 'SyntheticsLogHelper'」というエラーとなり失敗するので対処してみました。

CDKスタック

Canaryリソースを下記のようなCDKスタックで定義しました。

lib/aws-cdk-app-stack.ts

import * as path from 'path';
import * as cdk from '@aws-cdk/core';
import * as synthetics from '@aws-cdk/aws-synthetics';

export class AwsCdkAppStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    new synthetics.Canary(this, 'WebsiteCanary', {
      canaryName: `website-canary`,
      schedule: synthetics.Schedule.rate(cdk.Duration.minutes(10)),
      runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1,
      test: synthetics.Test.custom({
        code: synthetics.Code.fromAsset(
          path.join(__dirname, `../src/lambda/website-canary-handler`)
        ),
        handler: 'index.handler',
      }),
    });
  }
}

Canaryのスクリプトの内容については、今回の事象には関係が無いので割愛します。

cdk deployで上記スタックをデプロイし、Canaryリソースを作成しました。

事象

しかし作成したanaryの実行状況をAWSマネジメントコンソールでC確認すると、Cannot find module 'SyntheticsLogHelper'〜というエラーとなり実行が失敗しています。

Canary実行のログは下記となります。index.handler()を呼び出した直後にエラーが発生しているようです。

Start Canary
INFO: Event: {"canaryName":"website-canary","s3BaseFilePath":"awscdkappstack-websitecanaryartifactsbucketec81f5-XXXXXXXXXXXX","customerCanaryHandlerName":"index.handler","customerCanaryCodeLocation":"arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:layer:cwsyn-website-canary-bc36552f-2aff-4437-934a-d73f856f73cf:1","invocationTime":1631965835442,"runtimeVersion":"syn-nodejs-puppeteer-3.1","visualReference":null,"activeTracing":false,"canaryRunId":"3bda004c-bd49-438c-937a-024086abd9cb"}
INFO: Context: {"callbackWaitsForEmptyEventLoop":true,"functionVersion":"1","functionName":"cwsyn-website-canary-bc36552f-2aff-4437-934a-d73f856f73cf","memoryLimitInMB":"1000","logGroupName":"/aws/lambda/cwsyn-website-canary-bc36552f-2aff-4437-934a-d73f856f73cf","logStreamName":"2021/09/18/[1]b56f1fbe8393491b964edf57846b89a6","invokedFunctionArn":"arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:cwsyn-website-canary-bc36552f-2aff-4437-934a-d73f856f73cf:1","awsRequestId":"993e69cf-4187-403a-b1b9-e00be7ca9d3b"}
INFO: Configuring tracing: canaryName: website-canary canaryArn: arn:aws:synthetics:ap-northeast-1:XXXXXXXXXXXX:canary:website-canary canaryRunId: 3bda004c-bd49-438c-937a-024086abd9cb
INFO: Setting ActiveTracing to: false
INFO: Recording configuration: 
INFO: Canary execution start time: Sat Sep 18 2021 11:50:35 GMT+0000 (Coordinated Universal Time)
INFO: canaryName: website-canary
INFO: s3BaseFilePath: awscdkappstack-websitecanaryartifactsbucketec81f5-XXXXXXXXXXXX
INFO: awsAccountId: XXXXXXXXXXXX
INFO: region: ap-northeast-1
INFO: canaryArn: arn:aws:synthetics:ap-northeast-1:XXXXXXXXXXXX:canary:website-canary
INFO: memoryLimitInMB: 1000
INFO: awsRequestId: 993e69cf-4187-403a-b1b9-e00be7ca9d3b
INFO: timeRemainingInMillis: 599962
INFO: Launching Puppeteer browser with options: {"args":["--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--disk-cache-size=33554432","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-gl=swiftshader","--use-mock-keychain","--single-process"],"defaultViewport":{"deviceScaleFactor":1,"hasTouch":false,"height":1080,"isLandscape":true,"isMobile":false,"width":1920},"headless":true,"executablePath":"/tmp/chromium"}
INFO: Creating a new page.
INFO: Setting up page events.
INFO: Adding CloudWatchSynthetics/arn:aws:synthetics:ap-northeast-1:XXXXXXXXXXXX:canary:website-canary to user agent header sent with each outbound request.
INFO: Creating Puppeteer HAR object.
INFO: Starting HAR file logging.
INFO: Start executing customer steps
INFO: Customer canary entry file name: "index"
INFO: Customer canary entry function name: "handler"
INFO: Calling customer canary: /opt/nodejs/node_modules/index.handler()
ERROR: Canary error: 
Error: Cannot find module 'SyntheticsLogHelper'Require stack:- /opt/nodejs/node_modules/index.js- /var/task/index.js- /var/runtime/UserFunction.js- /var/runtime/index.js
INFO: Har generation stopped
INFO: Browser closed
INFO: Publishing result and duration CloudWatch metrics with timestamp: Sat Sep 18 2021 11:50:35 GMT+0000 (Coordinated Universal Time) for canaryName: website-canary stepName: null result: FAILED startDateTimeInUTC: Sat Sep 18 2021 11:50:40 GMT+0000 (Coordinated Universal Time) endDateTimeInUTC: Sat Sep 18 2021 11:50:40 GMT+0000 (Coordinated Universal Time)
INFO: Getting list of files under /tmp to upload to S3.
INFO: Checking list of files under /tmp to see if they are actual files.
INFO: List of actual files under /tmp ["/tmp/2021-09-18T11-50-36-721Z-log.txt","/tmp/SyntheticsReport-FAILED.json"]
INFO: Uploading files to S3 ["/tmp/2021-09-18T11-50-36-721Z-log.txt","/tmp/SyntheticsReport-FAILED.json"]
INFO: Getting S3 location for uploading files
INFO: S3 destination for uploading artifacts determined: {"s3Bucket":"awscdkappstack-websitecanaryartifactsbucketec81f5-XXXXXXXXXXXX","s3Key":"canary/ap-northeast-1/website-canary/2021/09/18/11/50-35-442"}
ERROR: Unable to fetch S3 bucket location: Access Denied. Fallback to S3 client in current region: ap-northeast-1.

調査

エラーにてCannot find moduleとあったSyntheticsLogHelperについて調べると下記の情報がありました。

SyntheticsLogHelper クラスは、ランタイム syn-nodejs-puppeteer-3.2 以降で利用可能です。これは CloudWatch Synthetics ライブラリですでに初期化されており、Synthetics 構成で設定されています。スクリプトに依存関係としてこれを追加できます。このクラスを使用すると、URL、ヘッダー、およびエラーメッセージをサニタイズして、機密情報を編集できます。

現在利用しているランタイムは、下記の通りsyn-nodejs-puppeteer-3.1です。

lib/aws-cdk-app-stack.ts

    new synthetics.Canary(this, 'WebsiteCanary', {
      canaryName: `website-canary`,
      schedule: synthetics.Schedule.rate(cdk.Duration.minutes(10)),
      runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1,
      test: synthetics.Test.custom({
        code: synthetics.Code.fromAsset(
          path.join(__dirname, `../src/lambda/website-canary-handler`)
        ),
        handler: 'index.handler',
      }),
    });

よってランタイムを3.2に上げれば良さそうです。しかしCDKスタックでのサジェストではsyn-nodejs-puppeteer-3.2以上のランタイムが提示されません。どうやら現在利用しているのCDKバージョン(1.111.0)には3.1までのランタイムしか含まれていないようです。

対処

そこで、CDKバージョンを最新版(1.123.0)にアップグレードします。

するとCanaryのランタイムでsyn-nodejs-puppeteer-3.2が選択できるようになりました。

ランタイムを更新したCanaryリソースのコード。

lib/aws-cdk-app-stack.ts

    new synthetics.Canary(this, 'WebsiteCanary', {
      canaryName: `website-canary`,
      schedule: synthetics.Schedule.rate(cdk.Duration.minutes(10)),
      runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_2,
      test: synthetics.Test.custom({
        code: synthetics.Code.fromAsset(
          path.join(__dirname, `../lambda/synthetics-canary`),
        ),
        handler: 'index.handler',
      }),
    });

再度cdk deployしてCanaryを更新すると、エラーなく実行ができるようになりました。

おわりに

AWS CDKで実装したCanaryの実行が「Cannot find module 'SyntheticsLogHelper'」というエラーとなり失敗するので対処してみました。

今回CanaryをはじめてAWS CDKで実装しましたが、Canaryリソースを一つ作るだけでRoleやS3バケット、Lambdaなど周辺リソースは裏側でよろしく作ってくれるのは便利だと思いました。

参考

以上