

# 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`로 설정됩니다. 이 환경 변수는 원격 측정에 대한 함수의 시작 동작을 수정합니다. 이 환경 변수가 이미 있는 경우 필수 값으로 설정되어야 합니다.