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
handler
function. 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 module
as a dependency.import { synthetics } from '@amzn/synthetics-playwright';
-
Launch a browser using the Synthetics
Launch
function.const browser = await synthetics.launch();
-
Create a new Playwright page by using the Synthetics
newPage
function.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’sSuccessPercent
metric is emitted. TheSuccessPercent
metric for a step is100
for the canary run if the step succeeds, and0
if the step fails. The default istrue
. -
stepDurationMetric
– Determines if a step'sDuration
metric is emitted. TheDuration
metric 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 passingincludeRequestHeaders
as true andrestrictedHeaders
as['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 iflogRequest
is true. The default isfalse
. -
logResponseBody
– Whether to log response bodies along with the requests in canary logs. This configuration applies only iflogResponse
is true. The default isfalse
. -
logRequestHeaders
– Whether to log request headers along with the requests in canary logs. This configuration applies only iflogRequest
is true. The default isfalse
. -
logResponseHeaders
– Whether to log response headers along with the responses in canary logs. This configuration applies only iflogResponse
is 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 the2xx
metric (with theCanaryName
dimension) for this canary. The default istrue
. -
metric_4xx
– Whether to emit the4xx
metric (with theCanaryName
dimension) for this canary. The default istrue
. -
metric_5xx
– Whether to emit the5xx
metric (with theCanaryName
dimension) for this canary. The default istrue
. -
failedRequestsMetric
– Whether to emit thefailedRequests
metric (with theCanaryName
dimension) for this canary. The default istrue
. -
aggregatedFailedRequestsMetric
– Whether to emit thefailedRequests
metric (without theCanaryName
dimension) for this canary. The default istrue
. -
aggregated2xxMetric
– Whether to emit the2xx
metric (without theCanaryName
dimension) for this canary. The default istrue
. -
aggregated4xxMetric
– Whether to emit the4xx
metric (without theCanaryName
dimension) for this canary. The default istrue
. -
aggregated5xxMetric
– Whether to emit the5xx
metric (without theCanaryName
dimension) for this canary. The default istrue
.
Canary metric configurations
Configurations for other metrics emitted by CloudWatch Synthetics.
-
failedCanaryMetric
– Whether to emit theFailed
metric (with theCanaryName
dimension) for this canary. The default istrue
. -
aggregatedFailedCanaryMetric
– Whether to emit theFailed
metric (without theCanaryName
dimension) 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-arn
to 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