

# 使用 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 项目。例如，您可以在 IntelliJ IDEA 或 Visual Studio Code 等首选 IDE 中使用标准的 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 金丝雀类示例** 

此示例是让金丝雀向存储在 *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 环境变量获取的两个单独的 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-aws-cloudwatch-synthetics-sdk-java](https://github.com/aws/aws-cloudwatch-synthetics-sdk-java/tree/main) 下的自述文件。

```
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 针对此 Canary 发出的具有不同 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*。

 **Canary 指标配置** 

对 CloudWatch Synthetics 发出的其他指标的配置。
+ *failedCanaryMetric* – 网络访问分析器指定是否发出此金丝雀的 *Failed* 指标（含 CanaryName 维度）。默认值为 *true*。
+ *aggatedFailedCanaryMetric* – 指定是否发出此金丝雀的 *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`。此环境变量会修改函数用于遥测的启动行为。如果此环境变量已存在，则确保将其设置为所需值。