

# Playwright 런타임을 사용하여 Node.js 카나리 스크립트 작성
<a name="Synthetics_WritingCanary_Nodejs_Playwright"></a>

**Topics**
+ [Playwright 런타임을 위한 Node.js 카나리 파일 패키징](#Synthetics_canary_Nodejs_Playwright_package)
+ [기존 Playwright 스크립트를 변경하여 CloudWatch Synthetics 카나리로 사용](#CloudWatch_Synthetics_canary_edit_Playwright_script)
+ [CloudWatch Synthetics 구성](#Synthetics_canary_configure_Playwright_script)

## Playwright 런타임을 위한 Node.js 카나리 파일 패키징
<a name="Synthetics_canary_Nodejs_Playwright_package"></a>

 카나리 스크립트는 Synthetics 핸들러 코드가 포함된 `.js`(CommonJS 구문) 또는 `.mjs`(ES 구문) 파일, 그리고 코드가 의존하는 추가 패키지 및 모듈로 구성됩니다. ES(ECMAScript) 형식으로 생성된 스크립트는 확장명으로 .mjs를 사용하거나, "type": "module" 필드 세트가 있는 package.json 파일을 포함해야 합니다. Node.js Puppeteer 같은 여타 런타임과 달리, 스크립트를 특정 폴더 구조에 저장하지 않아도 됩니다. 스크립트를 직접 패키징할 수 있습니다. 선호하는 `zip` 유틸리티를 사용하여 루트에 핸들러 파일이 있는 `.zip` 파일을 생성합니다. 카나리 스크립트가 Synthetics 런타임에 포함되지 않은 추가 패키지 또는 모듈에 의존하는 경우, `.zip` 파일에 이러한 종속성을 추가할 수 있습니다. 이렇게 하려면 `npm install` 명령을 실행하여 함수의 필수 라이브러리를 `node_modules` 디렉터리에 설치할 수 있습니다. 다음 예제 CLI 명령은 `index.js` 또는 `index.mjs` 파일(Synthetics 핸들러)이 포함된 `my_deployment_package.zip`이라는 이름의 `.zip` 파일을 생성합니다. 이 예제에서는 `npm` 패키지 관리자를 사용하여 종속 항목을 설치합니다.

```
~/my_function
├── index.mjs
├── synthetics.json
├── myhelper-util.mjs    
└── node_modules
    ├── mydependency
```

루트에 프로젝트 폴더의 콘텐츠가 포함된 `.zip` 파일을 만듭니다. 다음 예제와 같이 `r`(재귀) 옵션을 사용하여 `zip`이 하위 폴더를 압축하도록 합니다.

```
zip -r my_deployment_package.zip .
```

Synthetics 구성 파일을 추가하여 CloudWatch Synthetics의 동작을 구성합니다. `synthetics.json` 파일을 생성하고, 진입점 또는 핸들러 파일과 동일한 경로에 이 파일을 저장할 수 있습니다.

선택에 따라, 원하는 폴더 구조에 진입점 파일을 저장할 수도 있습니다. 그러나 폴더 경로가 핸들러 이름에 지정되어 있어야 합니다.

 **핸들러 이름** 

스크립트 진입점의 파일 이름과 일치하도록 canary의 스크립트 진입점(핸들러)을 ` myCanaryFilename.functionName`으로 설정해야 합니다. 카나리를 ` myFolder/my_canary_filename.mjs` 같은 별도의 폴더에 저장할 수도 있습니다. 별도의 폴더에 저장하는 경우 스크립트 진입점에 해당 경로를 지정합니다(예: ` myFolder/my_canary_filename.functionName`).

## 기존 Playwright 스크립트를 변경하여 CloudWatch Synthetics 카나리로 사용
<a name="CloudWatch_Synthetics_canary_edit_Playwright_script"></a>

카나리로 사용할 Node.js 및 Playwright의 기존 스크립트를 편집할 수 있습니다. Playwright에 대한 자세한 내용은 [Playwright library](https://playwright.dev/docs/api/class-playwright) 설명서를 참조하세요.

` exampleCanary.mjs` 파일에 저장된 다음과 같은 Playwright 스크립트를 사용할 수 있습니다.

```
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();
```

아래의 단계를 수행하여 스크립트를 변환합니다.

1. `handler` 함수를 생성하고 내보냅니다. 핸들러는 스크립트의 진입점 함수입니다. 핸들러 함수의 이름을 선택할 수 있지만, 스크립트에 사용되는 함수는 카나리 핸들러에 사용되는 것과 동일해야 합니다. 스크립트 이름이 `exampleCanary.mjs`이고 핸들러 함수 이름이 `myhandler`인 경우, 카나리 핸들러의 이름은 `exampleCanary.myhandler`입니다. 다음 예제에서 핸들러 함수 이름은 `handler`입니다.

   ```
   exports.handler = async () => {
     // Your script here
     };
   ```

1. 를 종속 항목`Synthetics Playwright module`으로 가져옵니다.

   ```
   import { synthetics } from '@aws/synthetics-playwright';
   ```

1. Synthetics `Launch` 함수를 사용하여 브라우저를 시작합니다.

   ```
   const browser = await synthetics.launch();
   ```

1. Synthetics `newPage` 함수를 사용하여 새 Playwright 페이지를 생성합니다.

   ```
   const page = await synthetics.newPage();
   ```

이제 스크립트를 Synthetics 카나리로 실행할 준비가 되었습니다. 다음은 업데이트된 스크립트입니다.

 **ES6 형식의 업데이트된 스크립트** 

`.mjs` 확장명으로 저장된 스크립트 파일입니다.

```
import { synthetics } from '@aws/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();
    }
};
```

 **CommonJS 형식으로 업데이트된 스크립트** 

`.js` 확장명으로 저장된 스크립트 파일입니다.

```
const { synthetics } = require('@aws/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 구성
<a name="Synthetics_canary_configure_Playwright_script"></a>

`synthetics.json`이라는 이름의 선택적 JSON 구성 파일을 제공하여 Synthetics Playwright 런타임의 동작을 구성할 수 있습니다. 이 파일은 핸들러 파일과 동일한 위치에 패키징해야 합니다. 구성 파일은 선택 사항이지만, 구성 파일을 제공하지 않거나 구성 키가 누락된 경우 CloudWatch는 기본값을 가져옵니다.

 **구성 파일 패키징** 

지원되는 구성 값과 기본값은 다음과 같습니다.

```
{
    "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
}
```

 **단계 구성** 
+ `screenshotOnStepStart` – 단계를 시작하기 전에 Synthetics가 스크린샷을 캡처해야 하는지 결정합니다. 기본값은 `true`입니다.
+ `screenshotOnStepSuccess` - 단계가 성공한 후 Synthetics가 스크린샷을 캡처해야 하는지 결정합니다. 기본값은 `true`입니다.
+ `screenshotOnStepFailure` - 단계가 실패한 후 Synthetics가 스크린샷을 캡처해야 하는지 결정합니다. 기본값은 `true`입니다.
+ `continueOnStepFailure` - 단계가 실패한 후에도 스크립트를 계속할지 결정합니다. 기본값은 `false`입니다.
+ `stepSuccessMetric` - 단계의 ` SuccessPercent` 지표를 내보낼지 결정합니다. 단계가 성공할 경우 카나리 실행에 대한 단계의 `SuccessPercent` 지표는 `100`이고, 단계가 실패할 경우에는 `0`입니다. 기본값은 `true`입니다.
+ `stepDurationMetric` - 단계의 `Duration` 지표를 내보낼지 결정합니다. `Duration` 지표는 단계 실행의 지속 기간으로, 밀리초 단위로 내보냅니다. 기본값은 `true`입니다.

 **보고서 구성** 

CloudWatch Synthetics에서 생성한 모든 보고서(예: HAR 파일 및 Synthetics 단계 보고서)를 포함합니다. 민감한 데이터 수정 필드 `restrictedHeaders` 및 `restrictedUrlParameters`는 Synthetics에서 생성한 로그에도 적용됩니다.
+ `includeRequestHeaders` - 보고서에 요청 헤더를 포함할지 여부입니다. 기본값은 `false`입니다.
+ `includeResponseHeaders` - 보고서에 응답 헤더를 포함할지 여부입니다. 기본값은 `false`입니다.
+ `includeUrlPassword` - URL에 표시되는 암호를 포함할지 여부입니다. 기본적으로 URL에 표시되는 암호를 로그 및 보고서에서 삭제하여 민감한 데이터가 공개되는 것을 방지합니다. 기본값은 `false`입니다.
+ `includeRequestBody` - 보고서에 요청 본문을 포함할지 여부입니다. 기본값은 `false`입니다.
+ `includeResponseBody` - 보고서에 응답 본문을 포함할지 여부입니다. 기본값은 `false`입니다.
+ `restrictedHeaders` - 헤더가 포함된 경우 무시할 헤더 값 목록입니다. 이는 요청 헤더와 응답 헤더 모두에 적용됩니다. 예를 들어 `includeRequestHeaders`를 true로, `restrictedHeaders`를 `['Authorization']`으로 전달하여 자격 증명을 숨길 수 있습니다.
+ `restrictedUrlParameters` - 수정할 URL 경로 또는 쿼리 파라미터의 목록입니다. 이는 로그, 보고서, 오류에 표시되는 URL에 적용됩니다. 파라미터는 대소문자를 구분하지 않습니다. 별표(`*`)를 값으로 전달하여 모든 URL 경로 및 쿼리 파라미터 값을 수정할 수 있습니다. 기본값은 빈 배열입니다.
+ `har` - HTTP 아카이브(HAR)를 생성해야 하는지 결정합니다. 기본값은 `true`입니다.

다음은 보고서 구성 파일의 예입니다.

```
"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
```

 **로깅 구성** 

CloudWatch Synthetics에서 생성한 로그에 적용됩니다. 요청 및 응답 로그의 상세 수준을 제어합니다.
+ `logRequest` - 카나리 로그에 모든 요청을 로그할지 여부입니다. UI canary의 경우에는 브라우저에서 보낸 각 요청을 로그합니다. 기본값은 ` false`입니다.
+ `logResponse` - 카나리 로그에 모든 응답을 로그할지 여부입니다. UI canary의 경우에는 브라우저에서 수신한 모든 응답을 로그합니다. 기본값은 ` false`입니다.
+ `logRequestBody` - 카나리 로그에 요청과 함께 요청 본문을 로그할지 여부입니다. 이 구성은 `logRequest`가 true인 경우에만 적용됩니다. 기본값은 `false`입니다.
+ `logResponseBody` - 카나리 로그에 요청과 함께 응답 본문을 로그할지 여부입니다. 이 구성은 `logResponse`가 true인 경우에만 적용됩니다. 기본값은 `false`입니다.
+ `logRequestHeaders` - 카나리 로그에 요청과 함께 요청 헤더를 로그할지 여부입니다. 이 구성은 ` logRequest`가 true인 경우에만 적용됩니다. 기본값은 `false`입니다.
+ `logResponseHeaders` - 카나리 로그에 응답과 함께 응답 헤더를 로그할지 여부입니다. 이 구성은 ` logResponse`가 true인 경우에만 적용됩니다. 기본값은 `false`입니다.

 **HTTP 지표 구성** 

이 카나리에 대해 CloudWatch Synthetics에서 내보내는 HTTP 상태 코드가 서로 다른 네트워크 요청 수와 관련된 지표의 구성입니다.
+ `metric_2xx` - 이 카나리에 대한 `2xx` 지표를(`CanaryName` 측정기준과 함께) 내보낼지 여부입니다. 기본값은 ` true`입니다.
+ `metric_4xx` - 이 카나리에 대한 `4xx` 지표를(`CanaryName` 측정기준과 함께) 내보낼지 여부입니다. 기본값은 ` true`입니다.
+ `metric_5xx` - 이 카나리에 대한 `5xx` 지표를(`CanaryName` 측정기준과 함께) 내보낼지 여부입니다. 기본값은 ` true`입니다.
+ `failedRequestsMetric` - 이 카나리에 대한 ` failedRequests` 지표를(`CanaryName` 측정기준과 함께) 내보낼지 여부입니다. 기본값은 `true`입니다.
+ `aggregatedFailedRequestsMetric` - 이 카나리에 대한 ` failedRequests` 지표를(`CanaryName` 측정기준 없이) 내보낼지 여부입니다. 기본값은 `true`입니다.
+ `aggregated2xxMetric` - 이 카나리에 대한 `2xx` 지표를(`CanaryName` 측정기준 없이) 내보낼지 여부입니다. 기본값은 `true`입니다.
+ `aggregated4xxMetric` - 이 카나리에 대한 `4xx` 지표를(`CanaryName` 측정기준 없이) 내보낼지 여부입니다. 기본값은 `true`입니다.
+ `aggregated5xxMetric` - 이 카나리에 대한 `5xx` 지표를(`CanaryName` 측정기준 없이) 내보낼지 여부입니다. 기본값은 `true`입니다.

 **카나리 지표 구성** 

CloudWatch Synthetics에서 내보낸 다른 지표에 대한 구성입니다.
+ `failedCanaryMetric` - 이 카나리에 대한 `Failed` 지표를(`CanaryName` 측정기준과 함께) 내보낼지 여부입니다. 기본값은 ` true`입니다.
+ `aggregatedFailedCanaryMetric` - 이 카나리에 대한 ` Failed` 지표를(`CanaryName` 측정기준 없이) 내보낼지 여부입니다. 기본값은 `true`입니다.

 **기타 구성** 
+ `userAgent` - 사용자 에이전트에 추가할 문자열입니다. 사용자 에이전트는 요청 헤더에 포함된 문자열이며, 헤드리스 브라우저를 사용할 경우 사용자가 방문하는 웹 사이트의 브라우저를 식별합니다. CloudWatch Synthetics는 `CloudWatchSynthetics/{{canary-arn}} to the user agent`를 자동으로 추가합니다. 지정된 구성이 생성된 사용자 에이전트에 추가됩니다. 기본 사용자 에이전트 값은 빈 문자열입니다(`""`).

### CloudWatch Synthetics 환경 변수
<a name="Synthetics_canary_Nodejs_Playwright_script"></a>

환경 변수를 사용하여 로깅 수준 및 형식을 구성합니다.

 **로그 형식** 

CloudWatch Synthetics Playwright 런타임은 모든 카나리 실행에 대해 CloudWatch 로그를 생성합니다. 로그는 편리한 쿼리를 위해 JSON 형식으로 작성됩니다. 원하는 경우, 로그 형식을 `TEXT`로 변경할 수 있습니다.
+ `Environment variable name` – CW\_SYNTHETICS\_LOG\_FORMAT 
+ `Supported values` – JSON, TEXT 
+ `Default` – JSON 

 **로그 수준** 

`Debug` 모드를 활성화하면 상세 수준이 높아지긴 하지만, 문제 해결에 유용할 수 있습니다.
+ `Environment variable name` – CW\_SYNTHETICS\_LOG\_LEVEL
+ `Supported values` – TRACE, DEBUG, INFO, WARN, ERROR, FATAL 
+ `Default` – INFO