Java 插桩示例

本文档介绍了如何修改 Java 应用以使用开源 OpenTelemetry 框架收集跟踪记录和指标数据,以及如何将结构化 JSON 日志写入标准输出。本文档还介绍了您可以安装和运行的示例 Java Spring Boot 应用。该应用已配置为生成指标、跟踪记录和日志。无论您是否使用 Spring Boot 框架,步骤都是相同的。

如需详细了解插桩,请参阅以下文档:

手动和零代码插桩简介

本文档中所述的插桩依赖 OpenTelemetry 零代码插桩将遥测数据发送到您的 Google Cloud 项目。 对于 Java,零代码插桩是指将字节码动态注入库和框架以捕获遥测数据的做法。零代码插桩可以收集入站和出站 HTTP 调用等内容的遥测数据。如需了解详情,请参阅 Java 代理

OpenTelemetry 还提供了一个 API,用于向您自己的代码添加自定义插桩。OpenTelemetry 将其称为手动插桩。本文档未介绍手动插桩。如需查看有关该主题的示例和信息,请参阅手动插桩

准备工作

  1. Install the Google Cloud CLI.

  2. 配置 gcloud CLI 以使用您的联合身份。

    如需了解详情,请参阅使用联合身份登录 gcloud CLI

  3. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  4. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  5. Verify that billing is enabled for your Google Cloud project.

  6. Enable the Cloud Logging, Cloud Monitoring, and Cloud Trace APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    gcloud services enable logging.googleapis.com monitoring.googleapis.com cloudtrace.googleapis.com
  7. 如果您在 Cloud Shell、 Google Cloud资源或本地开发环境中运行示例,则只需具备本部分中列出的权限即可。对于生产应用,通常由服务账号提供用于写入日志、指标和跟踪记录数据的凭据。

    如需获得让示例应用写入日志、指标和跟踪记录数据所需的权限,请让管理员为您授予项目的以下 IAM 角色:

    如需获得查看日志、指标和跟踪记录数据所需的权限,请让管理员为您授予项目的以下 IAM 角色:

    如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

    您也可以通过自定义角色或其他预定义角色来获取所需的权限。

  8. 对应用进行插桩处理以收集跟踪记录、指标和日志

    如需对应用进行插桩处理以收集跟踪记录和指标数据,并将结构化 JSON 写入标准输出,请执行以下步骤,如本文档后续部分所述:

    1. 配置您的应用以使用 OpenTelemetry Java 代理
    2. 配置 OpenTelemetry
    3. 配置结构化日志记录
    4. 写入结构化日志

    配置您的应用以使用 OpenTelemetry Java 代理

    如需将应用配置为写入结构化日志并使用 OpenTelemetry 收集指标和跟踪记录数据,请更新应用的调用以使用 OpenTelemetry Java 代理。这种对应用进行插桩的方法称为自动插桩,因为它不需要修改应用代码。

    以下代码示例演示了一个 Dockerfile,用于下载 OpenTelemetry Java 代理 JAR 文件并更新命令行调用以传递 -javaagent 标志。

    如需查看完整示例,请点击 更多,然后选择在 GitHub 上查看

    RUN wget -O /opentelemetry-javaagent.jar https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.31.0/opentelemetry-javaagent.jar
    CMD sh -c "java -javaagent:/opentelemetry-javaagent.jar -cp app:app/lib/* com.example.demo.DemoApplication \
    	2>&1 | tee /var/log/app.log"

    或者,您还可以在 JAVA_TOOL_OPTIONS 环境变量中设置 -javaagent 标志:

    export JAVA_TOOL_OPTIONS="-javaagent:PATH/TO/opentelemetry-javaagent.jar"
    

    配置 OpenTelemetry

    OpenTelemetry Java 代理的默认配置使用 OTLP 协议导出跟踪记录和指标。它还会将 OpenTelemetry 配置为使用 W3C 跟踪记录上下文格式来传播跟踪记录上下文。此配置可确保 span 在跟踪记录中具有正确的父子关系。

    如需了解详情和配置选项,请参阅 OpenTelemetry Java 自动插桩

    配置结构化日志记录

    如需在写入标准输出的 JSON 格式日志中包含跟踪记录信息,请将应用配置为输出 JSON 格式的结构化日志。我们建议您使用 Log4j2 作为日志记录实现。以下代码示例展示了一个配置为使用 JSON 模板布局输出 JSON 结构化日志的 log4j2.xml 文件:

    <!-- Format JSON logs for the Cloud Logging agent
    https://cloud.google.com/logging/docs/structured-logging#special-payload-fields -->
    
    <!-- Log4j2's JsonTemplateLayout includes a template for Cloud Logging's special JSON fields
    https://logging.apache.org/log4j/2.x/manual/json-template-layout.html#event-templates -->
    <JsonTemplateLayout eventTemplateUri="classpath:GcpLayout.json">
      <!-- Extend the included GcpLayout to include the trace and span IDs from Mapped
      Diagnostic Context (MDC) so that Cloud Logging can correlate Logs and Spans
    
      Since log4j2 2.24.0, GcpLayout.json already includes trace context logging from MDC and
      the below additional fields are no longer needed -->
      <EventTemplateAdditionalField
        key="logging.googleapis.com/trace"
        format="JSON"
        value='{"$resolver": "mdc", "key": "trace_id"}'
      />
      <EventTemplateAdditionalField
        key="logging.googleapis.com/spanId"
        format="JSON"
        value='{"$resolver": "mdc", "key": "span_id"}'
      />
      <EventTemplateAdditionalField
        key="logging.googleapis.com/trace_sampled"
        format="JSON"
        value="true"
      />
    </JsonTemplateLayout>

    上述配置会从 SLF4J 的映射诊断上下文中提取有关活跃 span 的信息,并将该信息作为属性添加到日志中。然后,您可以使用这些属性将日志与跟踪记录相关联:

    • logging.googleapis.com/trace:与日志条目关联的跟踪记录的资源名称。
    • logging.googleapis.com/spanId:与日志条目关联的跟踪记录的 span ID。
    • logging.googleapis.com/trace_sampled:此字段的值必须是 truefalse

    如需详细了解这些字段,请参阅 LogEntry 结构。

    写入结构化日志

    如需写入关联到跟踪记录的结构化日志,请使用 SLF4J Logging API。例如,以下语句展示了如何调用 Logger.info() 方法:

    logger.info("handle /multi request with subRequests={}", subRequests);
    

    OpenTelemetry Java 代理使用 OpenTelemetry 上下文中当前活跃 span 的 span 上下文自动填充 SLF4J 的映射诊断上下文。然后,映射的诊断上下文会包含在 JSON 日志中,如配置结构化日志记录中所述。

    运行配置为收集遥测数据的示例应用

    示例应用使用不受制于供应商的格式,包括 JSON(用于日志)和 OTLP(用于指标和跟踪记录)以及 Spring Boot 框架。为了将遥测数据路由到 Google Cloud,此示例使用配置了 Google 导出器的 OpenTelemetry Collector。该应用有两个端点:

    • /multi 端点由 handleMulti 函数处理。该应用中的负载生成器会向 /multi 端点发出请求。此端点收到请求时,它会向本地服务器上的 /single 端点发送 3 到 7 个请求。

      /**
       * handleMulti handles an http request by making 3-7 http requests to the /single endpoint.
       *
       * <p>OpenTelemetry instrumentation requires no changes here. It will automatically generate a
       * span for the controller body.
       */
      @GetMapping("/multi")
      public Mono<String> handleMulti() throws Exception {
        int subRequests = ThreadLocalRandom