教程:使用 Instana 跟踪 SDK 仪器化自定义 Java HTTP 框架

Instana 代理程序支持许多 Java HTTP 框架,并且在大多数情况下,只要运行 Java 代理程序,就会立即支持现成的跟踪。

但是,如果具有不受支持的定制内部 HTTP 服务器,那么可以使用 Java Trace SDK 来为框架添加跟踪。

本教程说明了如何执行此操作。

示例代码

custom-http-sample 教程的示例代码可以在 github.com 中找到。 它实现了以下方案:

自定义 HTTP 服务器教程

如果运行该示例并打开 http://localhost:8080,那么将获得响应 Hello, Stan!。 但是,如果分析 Instana 中的调用,那么将看到跟踪已中断。

跟踪 1: 跟踪截图 01

跟踪 2: 跟踪截图 02

出局请求是使用 Apache HTTP 客户机实现的,该客户机受 Instana 的自动跟踪支持。 缺少的链接是定制 HTTP Server 上的条目范围(入局呼叫)GET /greeting

启用自定义跟踪 HTTP Server

对于受支持的框架,Instana 代理程序会自动检测 Java 应用程序。 对于定制 HTTP Server,我们需要添加一些注释,以告知 Instana 代理程序,哪些方法调用应该启动新的范围。

首先,添加 mvn 依赖关系

<dependency>
  <groupId>com.instana</groupId>
  <artifactId>instana-java-sdk</artifactId>
  <version>1.2.0</version>
</dependency>

其次,在定制 HTTP 服务器为 HTTP 请求的方法添加 @Span 注释。

@Span(type = Span.Type.ENTRY, value = "my-custom-http-server")
public String apply(Map<String, String> headers) {
  // ...
}

该注解告诉 Java 代理生成 ENTRY span(又称 "span")。 服务器 span)。

第三,将以下内容添加到 Instana 代理程序的 configuration.yaml 文件中,以告知它应该扫描包 com.instana.sample.* 中的 Java 类以获取 @Span 注释:

com.instana.plugin.javatrace:
  instrumentation:
    sdk:
      packages:
        - 'com.instana.sample'

现在,已检测到定制服务器,并且会看到针对 /name 的出局呼叫是从 /greeting 的入局呼叫触发的。

跟踪截图 03

但是,由于在入局呼叫和出局呼叫之间未传递跟踪标识,因此跟踪仍处于中断状态。

处理传入的跟踪标题

Instana 使用以下 HTTP 头将跟踪信息从一个服务传递到下一个服务:

  • X-INSTANA-T: 跟踪标识
  • X-INSTANA-S: 父范围标识
  • X-INSTANA-L: 级别 0 表示应该禁止跟踪,这对于运行状况检查可能很有用

为了关联客户 HTTP Server 中的跟踪上下文,需要将以下方法添加到 GreetingHandler

private void correlateTracing(Map<String, String> request) {
  String level = request.remove(SpanSupport.LEVEL);
  String traceId = request.remove(SpanSupport.TRACE_ID);
  String parentSpanId = request.remove(SpanSupport.SPAN_ID);

  if (SpanSupport.SUPPRESS.equals(level)) {
    SpanSupport.suppressNext();
  } else if (traceId != null && parentSpanId != null) {
    SpanSupport.inheritNext(traceId, parentSpanId);
  }
}

请注意,我们在评估头之后会将其移除,只保留原始头,因为将在不进行 Instana 跟踪的情况下发送这些头。

但是,不能仅在 apply() 中调用 correlateTracing(),因为在调用具有 @Span 注释的方法之前需要对头进行求值。 作为变通方法,可以将 apply() 方法重命名为 doApply(),并添加如下步骤:

@Override
public String apply(Map<String, String> headers) {
  correlateTracing(headers);
  return doApply(headers);
}


@Span(type = Span.Type.ENTRY, value = "my-custom-http-server")
private String doApply(Map<String, String> headers) {
  // ...
}

现在运行 curl http://localhost:8080 时,将在 Instana 中看到完整的跟踪

跟踪截图 04

正在添加标签

到目前为止,我们的 my-custom-http-server 范围只是一个通用 ENTRY 范围,没有任何其他注释。 如果查看细节,它们看起来挺空洞。

无注释的跨度

可以在活动 @Span 上下文中调用 SDK 的 SpanSupport.annotate() 方法,以向当前范围添加注释。 Instana 支持 OpenTracing 的部分语义约定,如 Java 跟踪 SDK 文档 中所述。 为了添加 HTTP 注释,请在 doApply() 方法的开头添加以下几行:

@Span(type = Span.Type.ENTRY, value = SPAN_NAME)
private String doApply(Map<String, String> headers) {
  SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.http.url", "http://localhost:8080/greeting");
  SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.http.method", "GET");
  SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.http.status_code", "200");
  // ...
}

现在,定制 HTTP Server 的 ENTRY 范围的详细信息将显示指定的 HTTP 元数据。

带注释的跨度

请注意,从 Jetty 到定制 HTTP 服务器的相应 EXIT 范围已具有 HTTP 元数据,因为客户机使用的是 Instana 的自动跟踪所支持的 Apache HTTP 客户机。

将跨度标记为错误

在某个时刻,您可能希望将呼叫标记为错误。 可通过添加 OpenTracing 的语义约定中指定的 error 标记来轻松完成此操作。

SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.error", "true");

添加此操作,使调用在 Instana 中显示为错误。

错跨

总结与展望

本教程展示了使用 Instana 的分布式跟踪,来检测定制 HTTP 框架所需的最重要 API。

有关 SDK 的完整参考信息,请查看 SDK 的 JavaDoc。 例如,@SpanParam@SpanReturn 注释使您能够非常轻松地捕获参数或返回值作为其他信息的远范围,这可能比在某些方案中显式调用 SpanSupport.annotate() 更方便。