

# canary 스크립트 작성
<a name="CloudWatch_Synthetics_Canaries_WritingCanary"></a>

다음 섹션에서는 canary 스크립트를 작성하는 방법과 canary를 다른 AWS 서비스 그리고 외부 종속성 및 라이브러리와 통합하는 방법에 대해 설명합니다.

**Topics**
+ [Java 런타임을 사용하여 카나리 스크립트 작성](Synthetics_WritingCanary_Java.md)
+ [Playwright 런타임을 사용하여 Node.js 카나리 스크립트 작성](Synthetics_WritingCanary_Nodejs_Playwright.md)
+ [Puppeteer 런타임을 사용하여 Node.js 카나리 스크립트 작성](CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs_Pup.md)
+ [Python canary 스크립트 작성](CloudWatch_Synthetics_Canaries_WritingCanary_Python.md)
+ [Node.js 다중 검사 블루프린트에 대한 JSON 구성 작성](CloudWatch_Synthetics_WritingCanary_Multichecks.md)

# Java 런타임을 사용하여 카나리 스크립트 작성
<a name="Synthetics_WritingCanary_Java"></a>

**Topics**
+ [카나리에 대한 Java 프로젝트 구조](#Synthetics_canary_Java_package)
+ [카나리 프로젝트 패키징](#Synthetics_canary_Java_package_canary)
+ [핸들러 이름](#Synthetics_canary_Java_handler)
+ [CloudWatch Synthetics 구성](#Synthetics_canary_Java_config)
+ [CloudWatch Synthetics 환경 변수](#Synthetics_canary_Java_variables)

## 카나리에 대한 Java 프로젝트 구조
<a name="Synthetics_canary_Java_package"></a>

Java에서 카나리를 생성하려면 코드를 작성하고, 컴파일하고, 컴파일된 아티팩트를 Synthetics에 배포해야 합니다. 다양한 방법으로 Java Lambda 프로젝트를 초기화할 수 있습니다. 예를 들어 선호하는 IDE(예: IntelliJ IDEA 또는 Visual Studio Code)의 표준 Java 프로젝트 설정을 사용할 수 있습니다. 또는 필요한 파일 구조를 수동으로 생성할 수 있습니다.

Synthetics Java 프로젝트에는 다음과 같은 일반 구조가 포함되어 있습니다.

```
/project-root
    └ src
        └ main
            └ java
                └ canarypackage // name of package
                |    └ ExampleCanary.java // Canary code file
                |    └ other_supporting_classes
                - resources
                     └ synthetics.json // Synthetics configuration file    
     └ build.gradle OR pom.xml
```

Maven 또는 Gradle을 사용하여 프로젝트를 빌드하고 종속성을 관리할 수 있습니다.

위 구조에서 `ExampleCanary` 클래스는 카나리의 진입점 또는 핸들러입니다.

 **Java canary 클래스 예제** 

이 예제에서 카나리가 *TESTING\$1URL* Lambda 환경 변수에 저장된 URL에 대한 get 요청을 실시합니다. 카나리는 Synthetics 런타임에서 제공하는 메서드를 사용하지 않습니다.

```
package canarypackage;

import java.net.HttpURLConnection;
import java.net.URL;

// Handler value: canary.ExampleCanary::canaryCode
public class ExampleCanary { 
  public void canaryCode() throws Exception{ 
      URL url = new URL(System.getenv("TESTING_URL"));
      HttpURLConnection con=(HttpURLConnection)url.openConnection();
      con.setRequestMethod("GET");
      con.setConnectTimeout(5000);
      con.setReadTimeout(5000);
      int status=con.getResponseCode();
      if(status!=200){
        throw new Exception("Failed to load " + url + ", status code: " + status);
      }
  }
}
```

Synthetics 제공 라이브러리 함수 `executeStep`을 사용하여 카나리를 모듈화하는 것이 좋습니다. 카나리는 URL1 및 URL2 환경 변수에서 조달된 2개의 다른 URL에 `get`을 호출합니다.

**참고**  
`executeStep` 기능을 사용하려면 카나리의 핸들러 메서드가 아래와 같이 Synthetics 유형의 파라미터를 가져와야 합니다.

```
package canarypackage;

import com.amazonaws.synthetics.Synthetics;
import java.net.HttpURLConnection;
import java.net.URL;

// Handler value: canary.ExampleCanary::canaryCode
public class ExampleCanary {
  public void canaryCode(Synthetics synthetics) throws Exception {
    createStep("Step1", synthetics, System.getenv("URL1"));
    createStep("Step2", synthetics, System.getenv("URL2"));
    return;
  }
  
  private void createStep(String stepName, Synthetics synthetics, String url) throws Exception{
    synthetics.executeStep(stepName,()->{
      URL obj=new URL(url);
      HttpURLConnection con=(HttpURLConnection)obj.openConnection();
      con.setRequestMethod("GET");
      con.setConnectTimeout(5000);
      con.setReadTimeout(5000);
      int status=con.getResponseCode();
      if(status!=200){
        throw new Exception("Failed to load" + url + "status code:" + status);
      }
      return null;
    }).get();
  }
}
```

## 카나리 프로젝트 패키징
<a name="Synthetics_canary_Java_package_canary"></a>

Synthetics는 *zip* 형식의 Java 카나리 코드를 수락합니다. zip은 카나리 코드의 클래스 파일, 타사 종속성의 jar 및 Synthetics 구성 파일로 구성됩니다.

Synthetics Java zip에는 다음과 같은 일반 구조가 포함되어 있습니다.

```
example-canary
    └ lib
    |  └ //third party dependency jars
       └ java-canary.jar
    └ synthetics.json
```

위의 프로젝트 구조에서 이 zip을 구축하려면 gradle(build.gradle) 또는 maven(pom.xml)을 사용할 수 있습니다. 다음 예를 참고하세요

Synthetics 라이브러리의 컴파일 시간 종속성 또는 인터페이스에 대한 자세한 내용은 [aws-cloudwatch-synthetics-sdk-java](https://github.com/aws/aws-cloudwatch-synthetics-sdk-java/tree/main)의 README를 참조하세요.

```
plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    // Third party dependencies 
    // example: implementation 'software.amazon.awssdk:s3:2.31.9'
    
    // Declares dependency on Synthetics interfaces for compiling only
    // Refer https://github.com/aws/aws-cloudwatch-synthetics-sdk-java for building from source.
    compileOnly 'software.amazon.synthetics:aws-cloudwatch-synthetics-sdk-java:1.0.0'}

test {
    useJUnitPlatform()
}

// Build the zip to be used as Canary code.
task buildZip(type: Zip) {

    archiveFileName.set("example-canary.zip")
    destinationDirectory.set(file("$buildDir"))
    
    from processResources
    into('lib') {
        from configurations.runtimeClasspath
        from(tasks.named("jar"))
    }
    from "src/main/java/resources/synthetics.json"
    
    doLast {
        println "Artifact written to: ${archiveFile.get().asFile.absolutePath}"
    }
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

tasks.named("build") {
    dependsOn "buildZip"
}
```

## 핸들러 이름
<a name="Synthetics_canary_Java_handler"></a>

핸들러 이름은 카나리의 진입점입니다. Java 런타임의 경우 핸들러의 형식은 다음과 같습니다.

```
<<full qualified name for canary class>>::<<name of the method to start the execution from>>
// for above code: canarypackage.ExampleCanary::canaryCode
```

## CloudWatch Synthetics 구성
<a name="Synthetics_canary_Java_config"></a>

`synthetics.json`이라는 선택적 JSON 구성 파일을 제공하여 Synthetics Java 런타임의 동작을 구성할 수 있습니다. 이 파일은 패키지 zip 파일의 루트 디렉터리에 패키징되어야 합니다. 구성 파일은 선택 사항이지만, 구성 파일을 제공하지 않거나 구성 키가 누락된 경우 CloudWatch는 기본값을 사용합니다.

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

```
{
    "step": {
        "stepSuccessMetric": true,
        "stepDurationMetric": true,
        "continueOnStepFailure": false,
        "stepsReport": true
    },
    "logging": {
        "logRequest": false,
        "logResponse": false
    },
    "httpMetrics": {
        "metric_2xx": true,
        "metric_4xx": true,
        "metric_5xx": true,
        "aggregated2xxMetric": true,
        "aggregated4xxMetric": true,
        "aggregated5xxMetric": true
    },
    "canaryMetrics": {
        "failedCanaryMetric": true,
        "aggregatedFailedCanaryMetric": true
    }
}
```

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

 **로깅 구성** 

CloudWatch Synthetics에서 생성한 로그에 적용됩니다. 요청 및 응답 로그의 상세 수준을 제어합니다.
+ *logRequest* - 카나리 로그에 모든 요청을 로그할지 여부를 지정합니다. 기본값은 false입니다.
+ *logResponse* - 카나리 로그에 모든 응답을 로그할지 여부를 지정합니다. 기본값은 false입니다.

 **HTTP 지표 구성** 

이 카나리에 대해 CloudWatch Synthetics에서 내보내는 HTTP 상태 코드가 서로 다른 네트워크 요청 수와 관련된 지표의 구성입니다.
+ *metric\$12xx* -이 카나리에 대한 *2xx* 지표(CanaryName 차원 포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.
+ *metric\$14xx* -이 카나리에 대한 *4xx* 지표(CanaryName 차원 포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.
+ *metric\$15xx* -이 카나리에 대한 *5xx* 지표(CanaryName 차원 포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.
+ *aggregated2xxMetric* -이 카나리에 대한 *2xx* 지표(CanaryName 차원 미포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.
+ *aggregated4xxMetric* -이 카나리에 대한 *4xx* 지표(CanaryName 차원 미포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.
+ *aggregated5xxMetric* -이 카나리에 대한 *5xx* 지표(CanaryName 차원 미포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.

 **카나리 지표 구성** 

CloudWatch Synthetics에서 내보낸 다른 지표에 대한 구성입니다.
+ *failedCanaryMetric* - Network Access Analyzer가 카나리에 대한 *Failed* 지표(CanaryName 차원 포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.
+ *aggregatedFailedCanaryMetric* -이 카나리에 대한 *Failed* 지표(CanaryName 차원 미포함)를 내보낼지 여부를 지정합니다. 기본값은 *true*입니다.

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

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

 **로그 형식** 

CloudWatch Synthetics Java 런타임은 모든 카나리 실행에 대해 CloudWatch 로그를 생성합니다. 로그는 편리한 쿼리를 위해 JSON 형식으로 작성됩니다. 로그 형식을 *TEXT*로 변경할 수 있습니다.
+ *환경 변수 이름* – CW\$1SYNTHETICS\$1LOG\$1FORMAT
+ *지원되는 값* - JSON, TEXT
+ *기본값* – JSON

 **로그 수준** 
+ *환경 변수 이름* - CW\$1SYNTHETICS\$1LOG\$1LEVEL
+ *지원되는 값* - TRACE, DEBUG, INFO, WARN, ERROR, FATAL
+ *기본값* – INFO

위의 환경 변수 외에도 Java 런타임에 대한 기본 환경 변수인 `AWS_LAMBDA-EXEC_WRAPPER` 환경 변수가 함수에 추가되고, 값은 `/opt/synthetics-otel-instrument`로 설정됩니다. 이 환경 변수는 원격 측정에 대한 함수의 시작 동작을 수정합니다. 이 환경 변수가 이미 있는 경우 필수 값으로 설정되어야 합니다.

# 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\$1SYNTHETICS\$1LOG\$1FORMAT 
+ `Supported values` – JSON, TEXT 
+ `Default` – JSON 

 **로그 수준** 

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

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

**Topics**
+ [Scratch에서 CloudWatch Synthetics canary 생성](#CloudWatch_Synthetics_Canaries_write_from_scratch)
+ [Node.js canary 파일 패키징](#CloudWatch_Synthetics_Canaries_package)
+ [기존 Puppeteer 스크립트를 변경하여 Synthetics canary로 사용](#CloudWatch_Synthetics_Canaries_modify_puppeteer_script)
+ [환경 변수](#CloudWatch_Synthetics_Environment_Variables)
+ [다른 AWS 서비스와 canary 통합](#CloudWatch_Synthetics_Canaries_AWS_integrate)
+ [canary가 고정 IP 주소를 사용하도록 지정](#CloudWatch_Synthetics_Canaries_staticIP)

## Scratch에서 CloudWatch Synthetics canary 생성
<a name="CloudWatch_Synthetics_Canaries_write_from_scratch"></a>

다음은 최소 Synthetics canary 스크립트 예입니다. 이 스크립트는 성공적인 실행으로 전달되고 문자열을 반환합니다. 실패한 canary가 어떻게 보이는지 확인하려면 `let fail = false;`를 `let fail = true;`로 변경합니다.

canary 스크립트의 진입점 함수를 정의해야 합니다. 파일이 카나리의 `ArtifactS3Location`으로 지정된 Amazon S3 위치에 어떻게 업로드되는지 보려면 `/tmp` 폴더 아래에 이러한 파일을 생성합니다. 모든 카나리 아티팩트는 유일하게 쓰기 가능한 디렉터리인 `/tmp`에 저장해야 합니다. 스크립트에서 생성한 스크린샷 또는 기타 파일에 대한 스크린샷 경로가 `/tmp`으로 설정되어 있는지 확인합니다. Synthetics는 ` /tmp`에 있는 파일을 S3 버킷에 자동으로 업로드합니다.

```
/tmp/<name>
```

스크립트가 실행되면 통과 또는 실패 상태 및 지속 시간 지표가 CloudWatch에 게시되고, `/tmp`의 파일이 S3 버킷에 업로드됩니다.

```
const basicCustomEntryPoint = async function () {

    // Insert your code here

    // Perform multi-step pass/fail check

    // Log decisions made and results to /tmp

    // Be sure to wait for all your code paths to complete 
    // before returning control back to Synthetics.
    // In that way, your canary will not finish and report success
    // before your code has finished executing

    // Throw to fail, return to succeed
    let fail = false;
    if (fail) {
        throw "Failed basicCanary check.";
    }

    return "Successfully completed basicCanary checks.";
};

exports.handler = async () => {
    return await basicCustomEntryPoint();
};
```

다음으로 Synthetics 로깅을 사용하도록 스크립트를 확장하고 AWS SDK를 사용하여 호출합니다. 데모를 위해 이 스크립트는 Amazon DynamoDB 클라이언트를 생성하고 DynamoDB listTables API를 호출합니다. 요청에 대한 응답을 로깅하고 요청이 성공했는지 여부에 따라 성공 또는 실패를 로깅합니다.

```
const log = require('@aws/synthetics-logger');
const AWS = require('aws-sdk');
// Require any dependencies that your script needs
// Bundle additional files and dependencies into a .zip file with folder structure
// nodejs/node_modules/additional files and folders

const basicCustomEntryPoint = async function () {

    log.info("Starting DynamoDB:listTables canary.");
    
    let dynamodb = new AWS.DynamoDB();
    var params = {};
    let request = await dynamodb.listTables(params);
    try {
        let response = await request.promise();
        log.info("listTables response: " + JSON.stringify(response));
    } catch (err) {
        log.error("listTables error: " + JSON.stringify(err), err.stack);
        throw err;
    }

    return "Successfully completed DynamoDB:listTables canary.";
};

exports.handler = async () => {
    return await basicCustomEntryPoint();
};
```

## Node.js canary 파일 패키징
<a name="CloudWatch_Synthetics_Canaries_package"></a>

 **syn-nodejs-puppeteer-11.0 이상의 경우** 

 이전 패키징 구조(syn-nodejs-puppeteer-10.0 이하)는 최신 버전에서 계속 지원됩니다.

다음 옵션 중 하나를 사용하여 스크립트를 생성합니다.
+ .js 파일(CommonJS 구문)
+ .mjs 파일(ES 모듈 구문)

ES 모듈의 경우 다음 옵션 중 하나를 사용합니다.
+ .js 파일(CommonJS 구문)
+ .mjs 파일(ES 모듈 구문)

아래에 패키지 구조가 정의되어 있습니다.
+ 루트 수준 핸들러 파일(index.js/index.mjs)
+ 선택적 구성 파일(synthetics.json)
+ node\$1modules의 추가 종속성(필요한 경우)

패키징 구조 예제:

```
  my_function/
├── index.mjs
├── synthetics.json
├── helper-utils.mjs
└── node_modules/
    └── dependencies
```

패키징하려면 아래 단계를 수행합니다.

1. 종속성(있는 경우)을 설치하세요.

   ```
   npm install
   ```

1. .zip 패키지를 생성하세요.

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

 **syn-nodejs-puppeteer-11.0 이하의 경우** 

Amazon S3를 사용하는 경우 다음 구조가 필요합니다.

```
  nodejs/
└── node_modules/
    └── myCanaryFilename.js
```

 **syn-nodejs-puppeteer-3.4 이상에서 선택적 하위 폴더 지원을 추가하는 방법:** 

```
nodejs/
└── node_modules/
    └── myFolder/
        └── myCanaryFilename.js
```

**참고**  
구성에서 핸들러 경로는 사용자의 파일 위치와 일치해야 합니다.

 **핸들러 이름** 

스크립트 진입점의 파일 이름과 일치하도록 canary의 스크립트 진입점(핸들러)을 ` myCanaryFilename.functionName`으로 설정해야 합니다. `syn-nodejs-puppeteer-3.4` 이전 버전의 런타임을 사용하는 경우 `functionName`은 `handler`여야 합니다. ` syn-nodejs-puppeteer-3.4` 이상을 사용 중인 경우 함수 이름을 핸들러로 선택할 수 있습니다. `syn-nodejs-puppeteer-3.4` 이상을 사용 중인 경우 canary를 별도의 폴더에 저장할 수도 있습니다(예: ` nodejs/node_modules/myFolder/my_canary_filename`). 별도의 폴더에 저장하는 경우 스크립트 진입점에 해당 경로를 지정합니다(예: ` myFolder/my_canary_filename.functionName`).

## 기존 Puppeteer 스크립트를 변경하여 Synthetics canary로 사용
<a name="CloudWatch_Synthetics_Canaries_modify_puppeteer_script"></a>

이 섹션에서는 Puppeteer 스크립트를 가져와서 Synthetics canary 스크립트로 실행하도록 수정하는 방법에 대해 설명합니다. Puppeteer에 대한 자세한 내용은 [Puppeteer API v1.14.0](https://github.com/puppeteer/puppeteer/blob/v1.14.0/docs/api.md)을 참조하세요.

다음 Puppeteer 스크립트 예로 시작하겠습니다.

```
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'example.png'});

  await browser.close();
})();
```

변환 단계는 다음과 같습니다.
+ `handler` 함수를 생성하고 내보냅니다. 핸들러는 스크립트의 진입점 함수입니다. ` syn-nodejs-puppeteer-3.4` 이전 버전의 런타임을 사용하는 경우 핸들러 함수의 이름을 `handler`로 지정해야 합니다. `syn-nodejs-puppeteer-3.4` 이상을 사용하는 경우 함수 이름은 맘대로 지정할 수 있지만 스크립트에서 사용되는 이름과 같아야 합니다. 또한 `syn-nodejs-puppeteer-3.4` 이상을 사용하는 경우 스크립트를 아무 폴더 아래에 저장하고 해당 폴더를 핸들러 이름의 일부로 지정할 수 있습니다.

  ```
  const basicPuppeteerExample = async function () {};
  
  exports.handler = async () => {
      return await basicPuppeteerExample();
  };
  ```
+ `Synthetics` 종속성을 사용합니다.

  ```
  var synthetics = require('@aws/synthetics-puppeteer');
  ```
+ `Synthetics.getPage` 함수를 사용하여 Puppeteer `Page` 객체를 가져옵니다.

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

  Synthetics.getPage 함수에 의해 반환되는 페이지 객체에는 로깅을 위해 구성된 **page.on** `request`, `response` 및 ` requestfailed` 이벤트가 있습니다. 또한 Synthetics에서는 페이지의 요청 및 응답에 대한 HAR 파일 생성을 설정하고 canary ARN을 페이지의 발신 요청의 사용자 에이전트 헤더에 추가합니다.

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

```
var synthetics = require('@aws/synthetics-puppeteer');  // Synthetics dependency

const basicPuppeteerExample = async function () {
    const page = await synthetics.getPage(); // Get instrumented page from Synthetics
    await page.goto('https://example.com');
    await page.screenshot({path: '/tmp/example.png'}); // Write screenshot to /tmp folder
};

exports.handler = async () => {  // Exported handler function 
    return await basicPuppeteerExample();
};
```

## 환경 변수
<a name="CloudWatch_Synthetics_Environment_Variables"></a>

canary를 생성할 때 환경 변수를 사용할 수 있습니다. 환경 변수를 사용하면 단일 canary 스크립트를 작성한 다음, 다양한 값과 함께 해당 스크립트를 사용하여 유사한 태스크가 있는 여러 canary를 빠르게 생성할 수 있습니다.

예를 들어 조직에 소프트웨어 개발의 다양한 단계에 대한 엔드포인트(예: `prod`, ` dev`, `pre-release`)가 있으며 이러한 엔드포인트 각각을 테스트하기 위해 canary를 생성해야 한다고 가정합니다. 소프트웨어를 테스트하는 단일 canary 스크립트를 작성한 다음, 세 개의 canary 각각을 생성할 때 엔드포인트 환경 변수에 대해 다양한 값을 지정할 수 있습니다. 그런 다음, canary를 생성할 때 스크립트 및 환경 변수에 사용할 값을 지정합니다.

환경 변수의 이름에는 문자, 숫자, 밑줄 문자가 포함될 수 있습니다. 이름은 문자로 시작해야 하며 2자 이상이어야 합니다. 환경 변수의 총 크기는 4KB를 초과할 수 없습니다. Lambda 예약 환경 변수를 환경 변수의 이름으로 지정할 수 없습니다. 예약된 환경 변수에 대한 자세한 내용은 [런타임 환경 변수](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime) 단원을 참조하세요.

**중요**  
환경 변수 키와 값은 AWS 소유 AWS KMS 키를 사용하여 저장 시 암호화됩니다. 그러나 클라이언트 측의 환경 변수는 암호화되지 않습니다. 환경 변수 키와 값에 민감한 정보를 저장하지 마세요.

다음 스크립트 예에서는 두 개의 환경 변수를 사용합니다. 이 스크립트는 웹 페이지를 사용할 수 있는지 여부를 확인하는 canary용입니다. 환경 변수를 사용하여 확인하는 URL과 사용하는 CloudWatch Synthetics 로그 수준을 모두 파라미터화합니다.

다음 함수는 `LogLevel`을 ` LOG_LEVEL` 환경 변수의 값으로 설정합니다.

```
 synthetics.setLogLevel(process.env.LOG_LEVEL);
```

다음 함수는 `URL`을 `URL` 환경 변수의 값으로 설정합니다.

```
const URL = process.env.URL;
```

다음 코드는 완전한 스크립트입니다. 이 스크립트를 사용하여 canary를 생성할 때 `LOG_LEVEL` 및 `URL` 환경 변수의 값을 지정합니다.

```
var synthetics = require('@aws/synthetics-puppeteer');
const log = require('@aws/synthetics-logger');

const pageLoadEnvironmentVariable = async function () {

    // Setting the log level (0-3)
    synthetics.setLogLevel(process.env.LOG_LEVEL);
    // INSERT URL here
    const URL = process.env.URL;

    let page = await synthetics.getPage();
    //You can customize the wait condition here. For instance,
    //using 'networkidle2' may be less restrictive.
    const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000});
    if (!response) {
        throw "Failed to load page!";
    }
    //Wait for page to render.
    //Increase or decrease wait time based on endpoint being monitored.
    await page.waitFor(15000);
    await synthetics.takeScreenshot('loaded', 'loaded');
    let pageTitle = await page.title();
    log.info('Page title: ' + pageTitle);
    log.debug('Environment variable:' + process.env.URL);

    //If the response status code is not a 2xx success code
    if (response.status() < 200 || response.status() > 299) {
        throw "Failed to load page!";
    }
};

exports.handler = async () => {
    return await pageLoadEnvironmentVariable();
};
```

### 스크립트에 환경 변수 전달
<a name="CloudWatch_Synthetics_Canaries_pass_variables"></a>

콘솔에서 canary를 생성할 때 스크립트에 환경 변수를 전달하려면 콘솔의 [**환경 변수(Environment variables)**] 섹션에서 환경 변수의 키 및 값을 지정합니다. 자세한 내용은 [canary 생성](CloudWatch_Synthetics_Canaries_Create.md) 단원을 참조하세요.

API 또는 AWS CLI를 통해 환경 변수를 전달하려면 `RunConfig` 섹션에서 ` EnvironmentVariables` 파라미터를 사용합니다. 다음은 `Environment` 및 `Region` 키가 있는 두 개의 환경 변수를 사용하는 canary를 생성하는 AWS CLI 명령의 예입니다.

```
aws synthetics create-canary --cli-input-json '{
   "Name":"nameofCanary",
   "ExecutionRoleArn":"roleArn",
   "ArtifactS3Location":"s3://amzn-s3-demo-bucket-123456789012-us-west-2",
   "Schedule":{
      "Expression":"rate(0 minute)",
      "DurationInSeconds":604800
   },
   "Code":{
      "S3Bucket": "canarycreation",
      "S3Key": "cwsyn-mycanaryheartbeat-12345678-d1bd-1234-abcd-123456789012-12345678-6a1f-47c3-b291-123456789012.zip",
      "Handler":"pageLoadBlueprint.handler"
   },
   "RunConfig": {
      "TimeoutInSeconds":60,
      "EnvironmentVariables": {
         "Environment":"Production",
         "Region": "us-west-1"
      }
   },
   "SuccessRetentionPeriodInDays":13,
   "FailureRetentionPeriodInDays":13,
   "RuntimeVersion":"syn-nodejs-2.0"
}'
```

## 다른 AWS 서비스와 canary 통합
<a name="CloudWatch_Synthetics_Canaries_AWS_integrate"></a>

모든 canary는 AWS SDK 라이브러리를 사용할 수 있습니다. canary를 다른 AWS 서비스와 통합하기 위해 canary를 작성할 때 이 라이브러리를 사용할 수 있습니다.

이렇게 하려면 canary에 다음 코드를 추가해야 합니다. 다음 예에서는 AWS Secrets Manager가 canary와 통합되는 서비스로 사용됩니다.
+ AWS SDK를 가져옵니다.

  ```
  const AWS = require('aws-sdk');
  ```
+ 통합하려는 AWS 서비스에 대한 클라이언트를 생성합니다.

  ```
  const secretsManager = new AWS.SecretsManager();
  ```
+ 클라이언트를 사용하여 해당 서비스에 대한 API 호출을 수행합니다.

  ```
  var params = {
    SecretId: secretName
  };
  return await secretsManager.getSecretValue(params).promise();
  ```

다음 canary 스크립트 코드 조각은 Secrets Manager와의 통합 예를 자세히 보여 줍니다.

```
var synthetics = require('@aws/synthetics-puppeteer');
const log = require('@aws/synthetics-logger');
 
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
 
const getSecrets = async (secretName) => {
    var params = {
        SecretId: secretName
    };
    return await secretsManager.getSecretValue(params).promise();
}
 
const secretsExample = async function () {
    let URL = "<URL>";
    let page = await synthetics.getPage();
    
    log.info(`Navigating to URL: ${URL}`);
    const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000});
    
    // Fetch secrets
    let secrets = await getSecrets("secretname")
   
    /**
    * Use secrets to login. 
    *
    * Assuming secrets are stored in a JSON format like:
    * {
    *   "username": "<USERNAME>",
    *   "password": "<PASSWORD>"
    * }
    **/
    let secretsObj = JSON.parse(secrets.SecretString);
    await synthetics.executeStep('login', async function () {
        await page.type(">USERNAME-INPUT-SELECTOR<", secretsObj.username);
        await page.type(">PASSWORD-INPUT-SELECTOR<", secretsObj.password);
        
        await Promise.all([
          page.waitForNavigation({ timeout: 30000 }),
          await page.click(">SUBMIT-BUTTON-SELECTOR<")
        ]);
    });
   
    // Verify login was successful
    await synthetics.executeStep('verify', async function () {
        await page.waitForXPath(">SELECTOR<", { timeout: 30000 });
    });
};

exports.handler = async () => {
    return await secretsExample();
};
```

## canary가 고정 IP 주소를 사용하도록 지정
<a name="CloudWatch_Synthetics_Canaries_staticIP"></a>

canary가 고정 IP 주소를 사용하도록 canary를 설정할 수 있습니다.

**canary가 고정 IP 주소를 사용하도록 지정하려면**

1. 새 VPC를 생성합니다. 자세한 내용은 [VPC에서 DNS 사용하기](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html) 단원을 참조하세요.

1. 새 인터넷 게이트웨이를 생성합니다. 자세한 내용은 [VPC에 인터넷 게이트웨이 추가](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html#working-with-igw) 단원을 참조하세요.

1. 새 VPC 내부에 퍼블릭 서브넷을 생성합니다.

1. VPC에 새 라우팅 테이블을 추가합니다.

1. `0.0.0.0/0`에서 인터넷 게이트웨이로 이동하는 경로를 새 라우팅 테이블에 추가합니다.

1. 새 라우팅 테이블을 퍼블릭 서브넷과 연결합니다.

1. 탄력적 IP 주소를 생성합니다. 자세한 내용은 [탄력적 IP 주소](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html) 단원을 참조하세요.

1. 새 NAT 게이트웨이를 생성하여 퍼블릭 서브넷 및 탄력적 IP 주소에 할당합니다.

1. VPC 내부에 프라이빗 서브넷을 생성합니다.

1. `0.0.0.0/0`에서 NAT 게이트웨이로 이동하는 경로를 VPC 기본 라우팅 테이블에 추가합니다.

1. canary를 생성합니다.

# Python canary 스크립트 작성
<a name="CloudWatch_Synthetics_Canaries_WritingCanary_Python"></a>

이 스크립트는 성공적인 실행으로 전달되고 문자열을 반환합니다. 실패한 canary가 어떻게 보이는지 확인하려면 fail = False를 fail = True로 변경합니다.

```
def basic_custom_script():
    # Insert your code here
    # Perform multi-step pass/fail check
    # Log decisions made and results to /tmp
    # Be sure to wait for all your code paths to complete 
    # before returning control back to Synthetics.
    # In that way, your canary will not finish and report success
    # before your code has finished executing
    fail = False
    if fail:
        raise Exception("Failed basicCanary check.")
    return "Successfully completed basicCanary checks."
def handler(event, context):
    return basic_custom_script()
```

## Python canary 파일 패키징
<a name="CloudWatch_Synthetics_Canaries_WritingCanary_Python_package"></a>

.py 파일이 두 개 이상 있거나 스크립트에 종속 항목이 있는 경우 이들을 모두 단일 ZIP 파일로 번들링할 수 있습니다. `syn-python-selenium-1.1` 런타임을 사용하는 경우 ZIP 파일은 `python` 폴더 내에 주요 canary .py 파일을 포함해야 합니다(예: `python/my_canary_filename.py`). ` syn-python-selenium-1.1` 이상을 사용하는 경우 다른 폴더를 사용할 수 있습니다(예: `python/myFolder/my_canary_filename.py`).

이 ZIP 파일은 필요한 모든 폴더와 파일을 포함해야 하지만, `python` 폴더의 다른 파일을 포함하지 않아도 됩니다.

스크립트 진입점의 파일 이름 및 함수 이름과 일치하도록 canary의 스크립트 진입점을 ` my_canary_filename.functionName`으로 설정해야 합니다. `syn-python-selenium-1.0` 런타임을 사용하는 경우 `functionName`은 `handler`여야 합니다. ` syn-python-selenium-1.1` 이상을 사용 중인 경우 이 핸들러 이름 제한은 적용되지 않으며 canary를 별도의 폴더에 저장할 수도 있습니다(예: ` python/myFolder/my_canary_filename.py`). 별도의 폴더에 저장하는 경우 스크립트 진입점에 해당 경로를 지정합니다(예: ` myFolder/my_canary_filename.functionName`).

## 기존 Selenium 스크립트를 변경하여 Synthetics canary로 사용
<a name="CloudWatch_Synthetics_Canaries_WritingCanary_Python_Selenium"></a>

canary로 사용할 기존의 Python 및 Selenium 스크립트를 빠르게 수정할 수 있습니다. Selenium에 대한 자세한 내용은 [www.selenium.dev/](https://www.selenium.dev/)를 참조하세요.

이 예에서는 다음 Selenium 스크립트로 시작합니다.

```
from selenium import webdriver

def basic_selenium_script():
    browser = webdriver.Chrome()
    browser.get('https://example.com')
    browser.save_screenshot('loaded.png')

basic_selenium_script()
```

변환 단계는 다음과 같습니다.

**canary로 사용할 Selenium 스크립트를 변환하려면**

1. 다음과 같이 ` aws_synthetics` 모듈의 Selenium을 사용하도록 `import` 문을 변경합니다.

   ```
   from aws_synthetics.selenium import synthetics_webdriver as webdriver
   ```

   `aws_synthetics`의 Selenium 모듈은 canary가 지표 및 로그를 내보내고 HAR 파일을 생성하며 다른 CloudWatch Synthetics 기능과 함께 작동할 수 있도록 합니다.

1. 핸들러 함수를 생성하고 Selenium 메서드를 호출합니다. 핸들러는 스크립트의 진입점 함수입니다.

   `syn-python-selenium-1.0`을 사용하는 경우 핸들러 함수의 이름을 `handler`로 지정해야 합니다. `syn-python-selenium-1.1` 이상을 사용하는 경우 함수 이름은 맘대로 지정할 수 있지만 스크립트에서 사용되는 이름과 같아야 합니다. 또한 `syn-python-selenium-1.1` 이상을 사용하는 경우 스크립트를 아무 폴더 아래에 저장하고 해당 폴더를 핸들러 이름의 일부로 지정할 수 있습니다.

   ```
   def handler(event, context):
       basic_selenium_script()
   ```

이제 스크립트가 CloudWatch Synthetics canary로 업데이트되었습니다. 다음은 업데이트된 스크립트입니다.

`webdriver`는 [SyntheticsWebDriver](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library_Python.html#CloudWatch_Synthetics_Library_Python_SyntheticsWebDriver) 클래스의 인스턴스이고, `webdriver.Chrome()`에서 반환하는 브라우저는 [SyntheticsBrowser](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library_Python.html#CloudWatch_Synthetics_Library_Python_SyntheticsBrowser)의 인스턴스입니다.

```
from aws_synthetics.selenium import synthetics_webdriver as webdriver

def basic_selenium_script():
    browser = webdriver.Chrome()
    browser.get('https://example.com')
    browser.save_screenshot('loaded.png')

def handler(event, context):
    basic_selenium_script()
```

## 비표준 인증서를 인증하도록 기존 Puppeteer Synthetics 스크립트 변경
<a name="Canaries_Non-Standard_Certificates"></a>

Synthetics canary의 중요한 사용 사례 중 하나는 자체 엔드포인트를 모니터링하는 것입니다. 외부 트래픽을 수용할 준비가 되지 않은 엔드포인트를 모니터링하려는 경우 이러한 모니터링으로 인해 신뢰할 수 있는 타사 인증 기관에서 서명한 적절한 인증서가 없는 경우가 있을 수 있습니다.

이 시나리오에 대해 다음과 같이 두 가지 해결 방법이 있습니다.
+ 클라이언트 인증서를 인증하려면 [Amazon CloudWatch Synthetics를 사용하여 인증을 검증하는 방법-2부](https://aws.amazon.com/blogs/mt/how-to-validate-authentication-using-amazon-cloudwatch-synthetics-part-2/)를 참조하십시오.
+ 자체 서명된 인증서를 인증하려면 [Amazon CloudWatch Synthetics에서 자체 서명된 인증서를 사용하여 인증을 검증하는 방법](https://aws.amazon.com/blogs/mt/how-to-validate-authentication-with-self-signed-certificates-in-amazon-cloudwatch-synthetics/)을 참조하십시오.

CloudWatch Synthetics canary를 사용할 때는 이 두 가지 옵션에만 국한되지 않습니다. canary 코드를 확장하여 이러한 특성을 확장하고 비즈니스 로직을 추가할 수 있습니다.

**참고**  
Python 런타임에서 실행되는 Synthetics canary는 기본적으로 ` --ignore-certificate-errors` 플래그가 활성화되어 있으므로 이러한 canary는 비표준 인증서 구성을 가진 사이트에 도달하는 데 문제가 없어야 합니다.

# Node.js 다중 검사 블루프린트에 대한 JSON 구성 작성
<a name="CloudWatch_Synthetics_WritingCanary_Multichecks"></a>

Node.js 다중 검사 블루프린트를 사용하면 단일 카나리 실행 내에서 여러 가지 검증 검사를 수행하는 카나리를 생성할 수 있습니다. 이 블루프린트는 여러 엔드포인트를 테스트하거나, 애플리케이션의 다양한 측면을 검증하거나, 일련의 관련된 검사를 순차적으로 수행하려는 경우에 유용합니다.

**Topics**
+ [루트 구성 구조](#root-configuration-structure)
+ [글로벌 설정](#global-settings)
+ [변수 및 데이터 관리](#variables-data-management)
+ [단계 정의](#step-definitions)
+ [검사 유형](#check-types)
+ [인증 방법](#authentication-methods)
+ [어설션 및 검증](#assertions-validation)
+ [데이터 추출](#data-extraction)

## 루트 구성 구조
<a name="root-configuration-structure"></a>

루트 구성은 고급 API 블루프린트 카나리의 전체 구조를 정의합니다.


**스키마 속성**  

| 속성 | Type | 필수 | 설명 | 
| --- | --- | --- | --- | 
|  globalSettings  | 객체 | 아니요 | 모든 단계에 적용되는 기본 구성 | 
|  variables  | 객체 | 아니요 | 단계 전체에서 재사용 가능한 값(최대 10개) | 
|  steps  | 객체 |  예  | 모니터링 단계 수집(1\$110단계) | 

 **예제** 

```
{
  "globalSettings": {
    "stepTimeout": 30000,
    "userAgent": "CloudWatch-Synthetics-Advanced/1.0"
  },
  "variables": {
    "baseUrl": "https://api.example.com",
    "apiVersion": "v1"
  },
  "steps": {
    "1": {
      "stepName": "healthCheck",
      "checkerType": "HTTP",
      "url": "${baseUrl}/health",
      "httpMethod": "GET"
    }
  }
}
```

 **검증 규칙** 
+ 하나 이상의 단계를 포함해야 함
+ 최대 10단계 허용
+ `globalSettings`, ` variables`, `steps` 이외의 추가 속성은 허용되지 않음

## 글로벌 설정
<a name="global-settings"></a>

전역 설정은 단계 수준에서 재정의되지 않는 한 모든 단계에 적용되는 기본 구성을 제공합니다.

 **속성** 


**전역 설정 속성**  

| 속성 | Type | 기본값 | Range | 설명 | 
| --- | --- | --- | --- | --- | 
|  stepTimeout  | 정수 | 30000 | 5000\$1300000 | 모든 단계의 기본 제한 시간(밀리초) | 

 **예제** 

```
{
  "globalSettings": {
    "stepTimeout": 60000,
            
  }
}
```

## 변수 및 데이터 관리
<a name="variables-data-management"></a>

변수를 사용하면 `${variableName}` 구문을 사용하여 구성 전체에서 참조할 수 있는 재사용 가능한 값을 정의할 수 있습니다.

 **변수 속성** 


| 속성 | Type | 설명 | 
| --- | --- | --- | 
| 변수 이름 | 문자열 | ^[a-zA-Z][a-zA-Z0-9\$1]\$1\$1 패턴과 일치해야 함 | 
| 변수 값 | 문자열 | 문자열 값 | 

 **제한 사항 ** 
+ 구성당 최대 10개의 변수
+ 변수 이름은 문자로 시작해야 함
+ 변수 이름에는 문자, 숫자, 밑줄을 포함할 수 있음
+ 스키마에 지정되지 않은 최대 길이

 **예제** 

```
{
  "variables": {
    "baseUrl": "https://api.example.com",
    "apiKey": "${AWS_SECRET:my-api-key}",
    "timeout": "30000",
    "userEmail": "test@example.com"
  }
}
```

 **구성 사용** 

```
{
  "steps": {
    "1": {
      "url": "${baseUrl}/users",
      "timeout": "${timeout}",
      "headers": {
        "Authorization": "Bearer ${apiKey}"
      }
    }
  }
}
```

## 단계 정의
<a name="step-definitions"></a>

단계는 개별 모니터링 작업을 정의합니다. 각 단계에는 1\$110까지의 번호가 지정되며 특정 유형의 검사가 포함됩니다.

 *공통 단계 속성* 


| 속성 | Type | 필수 | 설명 | 
| --- | --- | --- | --- | 
|  stepName  | 문자열 |  예  | 단계의 고유 식별자 | 
|  checkerType  | 문자열 |  예  | 검사 유형: HTTP, DNS, SSL,  TCP  | 
|  extractors  | 배열 | 아니요 | 데이터 추출 구성 | 

 *단계 이름 검증* 
+ 패턴 - ^[a-zA-Z][a-zA-Z0-9\$1-]\$1\$1
+ 최대 길이 - 64자
+ 문자로 시작해야 함

 *단계 번호 지정* 
+ 단계는 문자열 키로 번호가 지정됨: "1", "2", ..., "10"
+ 패턴: ^([1-9]\$110)\$1
+ 최소 1개의 단계 필요
+ 최대 10단계 허용

 *예제* 

```
{
  "steps": {
    "1": {
      "stepName": "loginAPI",
      "checkerType": "HTTP",
      "url": "https://api.example.com/login",
      "httpMethod": "POST"
    },
    "2": {
      "stepName": "dnsCheck",
      "checkerType": "DNS",
      "domain": "example.com"
    }
  }
}
```

## 검사 유형
<a name="check-types"></a>

### HTTP 검사
<a name="http-types"></a>

포괄적인 요청 및 응답 검증을 통해 웹 엔드포인트 및 API를 모니터링합니다.

 **필수 속성** 


| 속성 | Type | 설명 | 
| --- | --- | --- | 
|  url  | 문자열 | 대상 URL(올바른 URI 형식이어야 함) | 
|  httpMethod  | 문자열 | HTTP 메서드: GET, POST, PUT,  PATCH, DELETE, HEAD, OPTIONS  | 

 **선택적 속성** 


| 속성 | Type | 기본값 | Range | 설명 | 
| --- | --- | --- | --- | --- | 
|  timeout  | 정수 | 30000 | 5000\$1300000 | 요청 제한 시간(밀리초) | 
|  waitTime  | 정수 | 0 | 0-60 | 요청까지 걸리는 지연 시간(초) | 
|  headers  | 객체 | - | - | 사용자 지정 HTTP 헤더 | 
|  body  | 문자열 | - | - | POST/PUT 작업에 대한 요청 본문 | 
|  authentication  | 객체 | - | - | 인증 구성 | 
|  assertions  | 배열 | - | - | 응답 검증 규칙 | 

 **예제** 

```
{
  "stepName": "createUser",
  "checkerType": "HTTP",
  "url": "https://api.example.com/users",
  "httpMethod": "POST",
  "timeout": 15000,
  "headers": {
    "Content-Type": "application/json",
    "X-API-Version": "v1"
  },
  "body": "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}",
  "authentication": {
    "type": "API_KEY",
    "apiKey": "${AWS_SECRET:api-credentials}",
    "headerName": "X-API-Key"
  },
  "assertions": [
    {
      "type": "STATUS_CODE",
      "operator": "EQUALS",
      "value": 201
    }
  ]
}
```

### DNS 검사
<a name="dns-types"></a>

DNS 확인 및 레코드 정보를 검증합니다.

 **필수 속성** 


| 속성 | Type | 설명 | 
| --- | --- | --- | 
|  domain  | 문자열 | 쿼리할 도메인 이름(호스트 이름 형식) | 

 **선택적 속성** 


| 속성 | Type | 기본값 | 설명 | 
| --- | --- | --- | --- | 
|  recordType  | 문자열 | "A" | DNS 레코드 유형: A, CNAME, MX,  TXT, NS  | 
|  nameserver  | 문자열 | - | 쿼리할 특정 DNS 서버 | 
|  timeout  | 정수 | 30000 | 쿼리 제한 시간(5000\$1300000ms) | 
|  port  | 정수 | 53 | DNS 서버 포트(1\$165535) | 
|  protocol  | 문자열 | "UDP" | 프로토콜: UDP 또는 TCP | 
|  assertions  | 배열 | - | DNS 응답 검증 규칙 | 

 **예제** 

```
{
  "stepName": "dnsResolution",
  "checkerType": "DNS",
  "domain": "example.com",
  "recordType": "A",
  "nameserver": "8.8.8.8",
  "timeout": 10000,
  "assertions": [
    {
      "type": "RECORD_VALUE",
      "operator": "CONTAINS",
      "value": "192.168"
    }
  ]
}
```

### SSL 검사
<a name="ssl-types"></a>

SSL 인증서 상태 및 구성을 모니터링합니다.

 **필수 속성** 


| 속성 | Type | 설명 | 
| --- | --- | --- | 
|  hostname  | 문자열 | 대상 호스트 이름(호스트 이름 형식) | 

 **선택적 속성** 


| 속성 | Type | 기본값 | 설명 | 
| --- | --- | --- | --- | 
|  port  | 정수 | 443 | SSL 포트(1\$165535) | 
|  timeout  | 정수 | 30000 | 연결 제한 시간(5000\$1300000ms) | 
|  sni  | 부울 | TRUE | 서버 이름 표시 | 
|  verifyHostname  | 부울 | TRUE | 호스트 이름 확인 | 
|  allowSelfSigned  | 부울 | FALSE | 자체 서명 인증서 수락 | 
|  assertions  | 배열 | - | 인증서 검증 규칙 | 

 **예제** 

```
{
  "stepName": "sslCertCheck",
  "checkerType": "SSL",
  "hostname": "secure.example.com",
  "port": 443,
  "sni": true,
  "verifyHostname": true,
  "assertions": [
    {
      "type": "CERTIFICATE_EXPIRY",
      "operator": "GREATER_THAN",
      "value": 30,
      "unit": "DAYS"
    }
  ]
}
```

### TCP 검사
<a name="tcp-types"></a>

TCP 포트 연결 및 응답 검증을 테스트합니다.

 **필수 속성** 


| 속성 | Type | 설명 | 
| --- | --- | --- | 
|  hostname  | 문자열 | 대상 호스트 이름(호스트 이름 형식) | 
|  port  | 정수 | 대상 포트(1\$165535) | 

 **선택적 속성** 


| 속성 | Type | 기본값 | 설명 | 
| --- | --- | --- | --- | 
|  timeout  | 정수 | 30000 | 전체 제한 시간(5000\$1300000ms) | 
|  connectionTimeout  | 정수 | 3000 | 연결 제한 시간(5000\$1300000ms) | 
|  readTimeout  | 정수 | 2000 | 데이터 읽기 제한 시간(5000\$1300000ms) | 
|  sendData  | 문자열 | - | 연결 후 전송할 데이터 | 
|  expectedResponse  | 문자열 | - | 예상 응답 데이터 | 
|  encoding  | 문자열 | "UTF-8" | 데이터 인코딩: UTF-8, ASCII, HEX  | 
|  assertions  | 배열 | - | 연결 및 응답 검증 | 

 **예제** 

```
{
  "stepName": "databaseConnection",
  "checkerType": "TCP",
  "hostname": "db.example.com",
  "port": 3306,
  "connectionTimeout": 5000,
  "sendData": "SELECT 1",
  "expectedResponse": "1",
  "assertions": [
    {
      "type": "CONNECTION_SUCCESSFUL",
      "value": true
    }
  ]
}
```

## 인증 방법
<a name="authentication-methods"></a>

 **인증 없음** 

```
{
  "type": "NONE"
}
```

 **기본 인증** 


| 속성 | Type | 필수 | 설명 | 
| --- | --- | --- | --- | 
|  type  | 문자열 |  예  | "BASIC"이어야 합니다. | 
|  username  | 문자열 |  예  | 인증에 사용할 사용자 이름 | 
|  password  | 문자열 |  예  | 인증에 사용할 암호 | 

 **예제** 

```
{
  "type": "BASIC",
  "username": "admin",
  "password": "${AWS_SECRET:basic-auth:password}"
}
```

 **API 키 인증** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "API\$1KEY"이어야 합니다. | 
|  apiKey  | 문자열 |  예  | - | API 키 값 | 
|  headerName  | 문자열 | No | "X-API-Key" | API 키의 헤더 이름 | 

 **예제** 

```
{
  "type": "API_KEY",
  "apiKey": "${AWS_SECRET:api-credentials}",
  "headerName": "Authorization"
}
```

 **OAuth 클라이언트 자격 증명** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "OAUTH\$1CLIENT\$1CREDENTIALS"이어야 합니다. | 
|  tokenUrl  | 문자열 |  예  | - | OAuth 토큰 엔드포인트 URL | 
|  clientId  | 문자열 |  예  | - | OAuth 클라이언트 ID | 
|  clientSecret  | 문자열 |  예  | - | OAuth 클라이언트 보안 암호 | 
|  scope  | 문자열 | No | - | OAuth 범위 | 
|  audience  | 문자열 | No | - | OAuth 대상 | 
|  resource  | 문자열 | No | - | OAuth 리소스 | 
|  tokenApiAuth  | 배열 | 아니요 | - | 토큰 API 인증 메서드: BASIC\$1AUTH\$1HEADER, REQUEST\$1BODY  | 
|  tokenCacheTtl  | 정수 | 아니요 | 3600 | 토큰 캐시 TTL(최소 60초) | 

 **예제** 

```
{
  "type": "OAUTH_CLIENT_CREDENTIALS",
  "tokenUrl": "https://auth.example.com/oauth/token",
  "clientId": "${AWS_SECRET:oauth-creds:client_id}",
  "clientSecret": "${AWS_SECRET:oauth-creds:client_secret}",
  "scope": "read write",
  "tokenCacheTtl": 7200
}
```

 **AWS 서명(버전 4)** 


| 속성 | Type | 필수 | 설명 | 
| --- | --- | --- | --- | 
|  type  | 문자열 |  예  | "SIGV4"이어야 합니다. | 
|  service  | 문자열 |  예  | AWS 서비스의 이름(예: "execute-api") | 
|  region  | 문자열 |  예  | AWS 리전 | 
|  roleArn  | 문자열 |  예  | 서명을 위한 IAM 역할 ARN | 

 **예제** 

```
{
  "type": "SIGV4",
  "service": "execute-api",
  "region": "us-east-1",
  "roleArn": "arn:aws:iam::123456789012:role/SyntheticsRole"
}
```

## 어설션 및 검증
<a name="assertions-validation"></a>

### HTTP 어설션
<a name="http-assertions"></a>

 **상태 코드 어설션** 


| 속성 | Type | 필수 | 설명 | 
| --- | --- | --- | --- | 
|  type  | 문자열 |  예  | "STATUS\$1CODE"이어야 합니다. | 
|  operator  | 문자열 |  예  | EQUALS, NOT\$1EQUALS, GREATER\$1THAN,  LESS\$1THAN, IN\$1RANGE | 
|  value  | 정수 | 조건부 | HTTP 상태 코드(100\$1599) | 
|  rangeMin  | 정수 | 조건부 | 최소 범위 값(IN\$1RANGE에 사용) | 
|  rangeMax  | 정수 | 조건부 | 최대 범위 값(IN\$1RANGE에 사용) | 

```
{
  "type": "STATUS_CODE",
  "operator": "EQUALS",
  "value": 200
}
```

 **응답 시간 어설션** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "RESPONSE\$1TIME"이어야 합니다. | 
|  operator  | 문자열 |  예  | - | LESS\$1THAN, GREATER\$1THAN, EQUALS | 
|  value  | number |  예  | - | 시간 값(최소 0) | 
|  unit  | 문자열 | No | "MILLISECONDS" | "MILLISECONDS"이어야 합니다. | 

```
{
  "type": "RESPONSE_TIME",
  "operator": "LESS_THAN",
  "value": 500,
  "unit": "MILLISECONDS"
}
```

 **헤드 어설션** 


| 속성 | Type | 필수 | 설명 | 
| --- | --- | --- | --- | 
|  type  | 문자열 |  예  | "HEADER"이어야 합니다. | 
|  headerName  | 문자열 |  예  | 검증할 헤더 이름 | 
|  operator  | 문자열 |  예  | EQUALS, NOT\$1EQUALS, CONTAINS,  NOT\$1CONTAINS, REGEX\$1MATCH, EXIST | 
|  value  | 문자열/부울 | 조건부 | 예상 값(EXIST 연산자의 경우 부울) | 

```
{
  "type": "HEADER",
  "headerName": "Content-Type",
  "operator": "CONTAINS",
  "value": "application/json"
}
```

 **본문 어설션** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "BODY"이어야 합니다. | 
|  target  | 문자열 | No | "JSON" | JSON 또는 TEXT | 
|  path  | 문자열 | 조건부 | - | JSONPath(JSON 대상에 필요) | 
|  operator  | 문자열 |  예  | - | CONTAINS, NOT\$1CONTAINS, EQUALS,  NOT\$1EQUALS, EXISTS | 
|  value  | 문자열/부울 |  예  | - | 예상 값(EXISTS 연산자의 경우 부울) | 

```
{
  "type": "BODY",
  "target": "JSON",
  "path": "$.users[0].name",
  "operator": "EQUALS",
  "value": "John Doe"
}
```

### DNS 어설션
<a name="dns-assertions"></a>

 **레코드 값 어설션** 


| 속성 | Type | 필수 | Range | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "RECORD\$1VALUE"이어야 합니다. | 
|  operator  | 문자열 |  예  | - | EQUALS, NOT\$1EQUALS, CONTAINS,  NOT\$1CONTAINS, REGEX\$1MATCH | 
|  value  | 문자열 |  예  | - | 예상 레코드 값 | 

 **레코드 수 어설션** 


| 속성 | Type | 필수 | Range | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "RECORD\$1COUNT"이어야 합니다. | 
|  operator  | 문자열 |  예  | - | EQUALS, GREATER\$1THAN, LESS\$1THAN | 
|  value  | 정수 |  예  | ≥ 0 | 예상 개수(최소 0) | 

 **신뢰할 수 있는 어설션** 


| 속성 | Type | 필수 | Range | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "AUTHORITATIVE"이어야 합니다. | 
|  value  | 부울 |  예  | - | 예상되는 신뢰할 수 있는 상태 | 

 **TTL 어설션** 


| 속성 | Type | 필수 | Range | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "TTL"이어야 합니다. | 
|  operator  | 문자열 |  예  | - | EQUALS, GREATER\$1THAN, LESS\$1THAN | 
|  value  | 정수 |  예  | ≥ 0 | 예상 TTL(최소 0) | 

### SSL 어설션
<a name="ssl-assertions"></a>

 **인증서 만료 어설션** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "CERTIFICATE\$1EXPIRY"이어야 합니다. | 
|  operator  | 문자열 |  예  | - | GREATER\$1THAN, LESS\$1THAN | 
|  value  | 정수 |  예  | - | 시간 값(최소 0) | 
|  unit  | 문자열 | No | "DAYS" | DAYS, HOURS | 

 **인증서 제목 어설션** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "CERTIFICATE\$1SUBJECT"이어야 합니다. | 
|  field  | 문자열 |  예  | - | 제목 필드: CN, O, OU, C, ST, L  | 
|  operator  | 문자열 |  예  | - | CONTAINS, EQUALS, REGEX\$1MATCH | 
|  value  | 문자열 |  예  | - | 예상 필드 값 | 

 **인증서 발급자 어설션** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "CERTIFICATE\$1ISSUER"이어야 합니다. | 
|  field  | 문자열 |  예  | - | 발급자 필드: CN, O  | 
|  operator  | 문자열 |  예  | - | CONTAINS, EQUALS | 
|  value  | 문자열 |  예  | - | 예상 필드 값 | 

### TCP 어설션
<a name="tcp-assertions"></a>

 **연결 성공 어설션** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "CONNECTION\$1SUCCESSFUL"이어야 합니다. | 
|  value  | 부울 |  예  | - | 예상 연결 상태 | 

 **응답 데이터 어설션** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  type  | 문자열 |  예  | - | "RESPONSE\$1DATA"이어야 합니다. | 
|  operator  | 문자열 |  예  | - | CONTAINS, EQUALS, NOT\$1CONTAINS,  REGEX\$1MATCH, STARTS\$1WITH, ENDS\$1WITH | 
|  value  | 문자열 |  예  | - | 예상 응답 데이터 | 
|  encoding  | 문자열 | No | "UTF-8" | UTF-8, ASCII, HEX | 

## 데이터 추출
<a name="data-extraction"></a>

추출기를 사용하면 응답에서 데이터를 캡처하여 후속 단계에서 사용하거나, 보고 목적으로 사용할 수 있습니다.

 **추출 속성** 


| 속성 | Type | 필수 | 기본값 | 설명 | 
| --- | --- | --- | --- | --- | 
|  name  | 문자열 |  예  | - | 추출된 데이터의 변수 이름 | 
|  type  | 문자열 |  예  | - | 추출 유형: BODY | 
|  path  | 문자열 | No | - | 본문 추출을 위한 JSONPath  | 
|  regex  | 문자열 | No | - | 정규식 패턴 | 
|  regexGroup  | 정수 | 아니요 | 0 | 정규식 캡처 그룹(최소 0) | 

 **추출 이름 검증** 
+ 패턴: `^[a-zA-Z][a-zA-Z0-9_]*$`
+ 문자로 시작해야 함
+ 이름에 문자, 숫자, 밑줄을 포함할 수 있음

**제한 사항** - 특정 ENUM 값이 있는 스키마의 필드에는 대체가 적용되지 않습니다.

 **추출 유형** 

```
{
  "name": "userId",
  "type": "BODY",
  "path": "$.user.id"
}
```

```
{
  "stepName": "loginAndExtract",
  "checkerType": "HTTP",
  "url": "https://api.example.com/login",
  "httpMethod": "POST",
  "body": "{\"username\":\"test\",\"password\":\"pass\"}",
  "extractors": [
    {
      "name": "textVariable",
      "type": "BODY",
      "path": "$.myvalue"
    }
  ]
},
{
  "stepName": "substituteVariable",
  "checkerType": "HTTP",
  "url": "https://api.example.com/get/${textVariable}",
  "httpMethod": "GET",
  "assertions": [
    {
    "type": "BODY",
    "target": "JSON",
    "path": "$.users[0].name",
    "operator": "EQUALS",
    "value": "${textVariable}"
    }
  ]
}
```