Writing a Node.js canary script using the Playwright runtime
Topics
Packaging your Node.js canary files for the Playwright runtime
Your canary script comprises of a .js (CommonJS syntax) or
.mjs (ES syntax) file containing your Synthetics handler code, together
with any additional packages and modules your code depends on. Scripts created in ES
(ECMAScript) format should either use .mjs as the extension or include a package.json
file with the "type": "module" field set. Unlike other runtimes like Node.js Puppeteer,
you are not required to save your scripts in a specific folder structure. You can
package your scripts directly. Use your preferred zip utility to create a
.zip file with your handler file at the root. If your canary
script depends on additional packages or modules that aren't included in the Synthetics
runtime, you can add these dependencies to your .zip file. To do
so, you can install your function's required libraries in the
node_modules directory by running the npm install
command. The following example CLI commands create a .zip file
named my_deployment_package.zip containing the
index.js or index.mjs file (Synthetics
handler) and its dependencies. In the example, you install dependencies using the
npm package manager.
~/my_function ├── index.mjs ├── synthetics.json ├── myhelper-util.mjs └── node_modules ├── mydependency
Create a .zip file that contains the contents of your project
folder at the root. Use the r (recursive) option, as shown in the following
example, to ensure that zip compresses the subfolders.
zip -r my_deployment_package.zip .
Add a Synthetics configuration file to configure the behavior of CloudWatch Synthetics.
You can create a synthetics.json file and save it at the same path
as your entry point or handler file.
Optionally, you can also store your entry point file in a folder structure of your choice. However, be sure that the folder path is specified in your handler name.
Handler name
Be sure to set your canary’s script entry point (handler) as
myCanaryFilename.functionName to match the file name of your
script’s entry point. You can optionally store the canary in a separate folder such as
myFolder/my_canary_filename.mjs. If you store it in a separate
folder, specify that path in your script entry point, such as
myFolder/my_canary_filename.functionName.
Changing an existing Playwright script to use as a CloudWatch Synthetics canary
You can edit an existing script for Node.js and Playwright to be used as a canary.
For more information about Playwright, see the Playwright library
You can use the following Playwright script that is saved in file
exampleCanary.mjs.
import { chromium } from 'playwright'; import { expect } from '@playwright/test'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://example.com', {timeout: 30000}); await page.screenshot({path: 'example-home.png'}); const title = await page.title(); expect(title).toEqual("Example Domain"); await browser.close();
Convert the script by performing the following steps:
-
Create and export a
handlerfunction. The handler is the entry point function for the script. You can choose any name for the handler function, but the function that is used in your script should be the same as in your canary handler. If your script name isexampleCanary.mjs, and the handler function name ismyhandler, your canary handler is namedexampleCanary.myhandler. In the following example, the handler function name ishandler.exports.handler = async () => { // Your script here }; -
Import the
Synthetics Playwright moduleas a dependency.import { synthetics } from '@amzn/synthetics-playwright'; -
Launch a browser using the Synthetics
Launchfunction.const browser = await synthetics.launch(); -
Create a new Playwright page by using the Synthetics
newPagefunction.const page = await synthetics.newPage();
Your script is now ready to be run as a Synthetics canary. The following is the the updated script:
Updated script in ES6 format
The script file saved with a .mjs extension.
import { synthetics } from '@amzn/synthetics-playwright'; import { expect } from '@playwright/test'; export const handler = async (event, context) => { try { // Launch a browser const browser = await synthetics.launch(); // Create a new page const page = await synthetics.newPage(browser); // Navigate to a website await page.goto('https://www.example.com', {timeout: 30000}); // Take screenshot await page.screenshot({ path: '/tmp/example.png' }); // Verify the page title const title = await page.title(); expect(title).toEqual("Example Domain"); } finally { // Ensure browser is closed await synthetics.close(); } };
Updated script in CommonJS format
The script file saved with a .js extension.
const { synthetics } = require('@amzn/synthetics-playwright'); const { expect } = require('@playwright/test'); exports.handler = async (event) => { try { const browser = await synthetics.launch(); const page = await synthetics.newPage(browser); await page.goto('https://www.example.com', {timeout: 30000}); await page.screenshot({ path: '/tmp/example.png' }); const title = await page.title(); expect(title).toEqual("Example Domain"); } finally { await synthetics.close(); } };
CloudWatch Synthetics configurations
You can configure the behavior of the Synthetics Playwright runtime by providing an
optional JSON configuration file named synthetics.json. This file
should be packaged in the same location as the handler file. Though a configuration file
is optional, f you don't provide a configuration file, or a configuration key is
missing, CloudWatch assumes defaults.
Packaging your configuration file
The following are supported configuration values, and their defaults.
{ "step": { "screenshotOnStepStart": false, "screenshotOnStepSuccess": false, "screenshotOnStepFailure": false, "stepSuccessMetric": true, "stepDurationMetric": true, "continueOnStepFailure": true, "stepsReport": true }, "report": { "includeRequestHeaders": true, "includeResponseHeaders": true, "includeUrlPassword": false, "includeRequestBody": true, "includeResponseBody": true, "restrictedHeaders": ['x-amz-security-token', 'Authorization'], // Value of these headers is redacted from logs and reports "restrictedUrlParameters": ['Session', 'SigninToken'] // Values of these url parameters are redacted from logs and reports }, "logging": { "logRequest": false, "logResponse": false, "logResponseBody": false, "logRequestBody": false, "logRequestHeaders": false, "logResponseHeaders": false }, "httpMetrics": { "metric_2xx": true, "metric_4xx": true, "metric_5xx": true, "failedRequestsMetric": true, "aggregatedFailedRequestsMetric": true, "aggregated2xxMetric": true, "aggregated4xxMetric": true, "aggregated5xxMetric": true }, "canaryMetrics": { "failedCanaryMetric": true, "aggregatedFailedCanaryMetric": true }, "userAgent": "", "har": true }
Step configurations
-
screenshotOnStepStart– Determines if Synthetics should capture a screenshot before the step starts. The default istrue. -
screenshotOnStepSuccess– Determines if Synthetics should capture a screenshot after a step has succeeded. The default istrue. -
screenshotOnStepFailure– Determines if Synthetics should capture a screenshot after a step has failed. The default istrue. -
continueOnStepFailure– Determines if a script should continue even after a step has failed. The default isfalse. -
stepSuccessMetric– Determines if a step’sSuccessPercentmetric is emitted. TheSuccessPercentmetric for a step is100for the canary run if the step succeeds, and0if the step fails. The default istrue. -
stepDurationMetric– Determines if a step'sDurationmetric is emitted. TheDurationmetric is emitted as a duration, in milliseconds, of the step's run. The default istrue.
Report configurations
Includes all reports generated by CloudWatch Synthetics, such as a HAR file and a
Synthetics steps report. Sensitive data redaction fields restrictedHeaders
and restrictedUrlParameters also apply to logs generated by Synthetics.
-
includeRequestHeaders– Whether to include request headers in the report. The default isfalse. -
includeResponseHeaders– Whether to include response headers in the report. The default isfalse. -
includeUrlPassword– Whether to include a password that appears in the URL. By default, passwords that appear in URLs are redacted from logs and reports, to prevent the disclosure of sensitive data. The default isfalse. -
includeRequestBody– Whether to include the request body in the report. The default isfalse. -
includeResponseBody– Whether to include the response body in the report. The default isfalse. -
restrictedHeaders– A list of header values to ignore, if headers are included. This applies to both request and response headers. For example, you can hide your credentials by passingincludeRequestHeadersas true andrestrictedHeadersas['Authorization']. -
restrictedUrlParameters– A list of URL path or query parameters to redact. This applies to URLs that appear in logs, reports, and errors. The parameter is case-insensitive. You can pass an asterisk (*) as a value to redact all URL path and query parameter values. The default is an empty array. -
har– Determines if an HTTP archive (HAR) should be generated. The default istrue.
The following is an example of a report configurations file.
"includeRequestHeaders": true, "includeResponseHeaders": true, "includeUrlPassword": false, "includeRequestBody": true, "includeResponseBody": true, "restrictedHeaders": ['x-amz-security-token', 'Authorization'], // Value of these headers is redacted from logs and reports "restrictedUrlParameters": ['Session', 'SigninToken'] // Values of these URL parameters are redacted from logs and reports
Logging configurations
Applies to logs generated by CloudWatch Synthetics. Controls the verbosity of request and response logs.
-
logRequest– Whether to log every request in canary logs. For UI canaries, this logs each request sent by the browser. The default isfalse. -
logResponse– Whether to log every response in canary logs. For UI canaries, this logs every response received by the browser. The default isfalse. -
logRequestBody– Whether to log request bodies along with the requests in canary logs. This configuration applies only iflogRequestis true. The default isfalse. -
logResponseBody– Whether to log response bodies along with the requests in canary logs. This configuration applies only iflogResponseis true. The default isfalse. -
logRequestHeaders– Whether to log request headers along with the requests in canary logs. This configuration applies only iflogRequestis true. The default isfalse. -
logResponseHeaders– Whether to log response headers along with the responses in canary logs. This configuration applies only iflogResponseis true. The default isfalse.
HTTP metric configurations
Configurations for metrics related to the count of network requests with different HTTP status codes, emitted by CloudWatch Synthetics for this canary.
-
metric_2xx– Whether to emit the2xxmetric (with theCanaryNamedimension) for this canary. The default istrue. -
metric_4xx– Whether to emit the4xxmetric (with theCanaryNamedimension) for this canary. The default istrue. -
metric_5xx– Whether to emit the5xxmetric (with theCanaryNamedimension) for this canary. The default istrue. -
failedRequestsMetric– Whether to emit thefailedRequestsmetric (with theCanaryNamedimension) for this canary. The default istrue. -
aggregatedFailedRequestsMetric– Whether to emit thefailedRequestsmetric (without theCanaryNamedimension) for this canary. The default istrue. -
aggregated2xxMetric– Whether to emit the2xxmetric (without theCanaryNamedimension) for this canary. The default istrue. -
aggregated4xxMetric– Whether to emit the4xxmetric (without theCanaryNamedimension) for this canary. The default istrue. -
aggregated5xxMetric– Whether to emit the5xxmetric (without theCanaryNamedimension) for this canary. The default istrue.
Canary metric configurations
Configurations for other metrics emitted by CloudWatch Synthetics.
-
failedCanaryMetric– Whether to emit theFailedmetric (with theCanaryNamedimension) for this canary. The default istrue. -
aggregatedFailedCanaryMetric– Whether to emit theFailedmetric (without theCanaryNamedimension) for this canary. The default istrue.
Other configurations
-
userAgent– A string to append to the user agent. The user agent is a string that is included in request header, and identifies your browser to websites you visit when you use the headless browser. CloudWatch Synthetics automatically addsCloudWatchSynthetics/. The specified configuration is appended to the generated user agent. The default user agent value to append is an empty string (canary-arnto the user agent"").
CloudWatch Synthetics environment variables
Configure the logging level and format by using environment variables.
Log format
The CloudWatch Synthetics Playwright runtime creates CloudWatch logs for every canary run.
Logs are written in JSON format for convenient querying. Optionally, you can change
the log format to TEXT.
-
Environment variable name– CW_SYNTHETICS_LOG_FORMAT -
Supported values– JSON, TEXT -
Default– JSON
Log levels
Though enabling Debug mode increases verbosity, it can be useful for
troubleshooting.
-
Environment variable name– CW_SYNTHETICS_LOG_LEVEL -
Supported values– TRACE, DEBUG, INFO, WARN, ERROR, FATAL -
Default– INFO