Java 跟踪 SDK

通过使用 Instana Java Trace SDK (github ),可以手动检测 Instana 尚不知道的入口和出口,以及标记自定义代码中有趣的部分。 它还支持在二进制协议之间创建定制关联,并将定制定义的密钥值对添加到范围(用于抽取相关信息)。

配置

要使用基于配置的 Java 跟踪 SDK,您需要按照启用 Java 跟踪 SDK 中的说明启用 Java 跟踪 SDK。

自定义二进制协议的出口和入口

已发布的示例应用程序 ( https://github.com/instana/instana-java-sdk/tree/master/instana-java-sdk-sample ) 包含一个 CustomTCP 服务器和客户端,说明如何使用 SDK 来标记进入、退出和执行相关操作。

使用 instana-java-sdk

Java Trace SDK 要求您在应用程序中添加一个 jar 文件。 此 JAR 文件包含用于标记 Instana 应处理的代码部分的注释和帮助程序类。 使用 Maven 时,可以使用以下命令轻松添加依赖关系:

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

缺省 Maven 中央存储库中提供了 instana-java-sdk 工件。

当没有代理监控包含该库并标有注释的 JVM 部分时,它们将作为 No-Op 运行。 使用注释是安全的,只要没有代理程序在监视 JVM,这些注释就不会产生任何影响。 要让 Instana 代理程序实际使用这些注释,您必须告诉它哪些 Java 包名称具有这些注释。 这是因为扫描注释是一个繁重的过程,扫描大型应用程序的整个类路径可能需要很长时间。

必需的 configuration.yaml 部分如下所示:

# Java Tracing
com.instana.plugin.javatrace:
  instrumentation:
    # By default no packages are scanned for SDK annotations.
    sdk:
      packages:
        - 'com.mycompany.backend'
        - 'com.mycompany.frontend'

将以递归方式扫描这些包。 即,如果将 com.mycompany.backend 配置为扫描注释,那么也将扫描 com.mycompany.backend.impl 和其他子包。

标记中间体

要在中间范围标记某个方法,只需添加以下注释:

@Span(value = "custom-tcp-server")

中间值是 SDK 范围的缺省类型,如果未另行声明,那么将使用此值。 在应用程序中,这种类型的范围标记为“有趣”的方法,您希望更好地了解这些方法。。 请记住,这并不能取代像 Instana AutoProfile™ 这样的真实概要分析程序。

标记条目

要在“入口范围”中标记方法,只需添加以下注释,如以下示例中所示:

@Span(type = Type.ENTRY, value = "custom-tcp-server")

一旦 Instana 看到输入此方法的代码,就会启动跟踪。 入口范围通常指示来自外部系统或已调度任务的入局呼叫。

标记出口

要在“出口范围”中标记方法,只需添加以下注释,如以下示例中所示:

@Span(type = Type.EXIT, value = "custom-tcp-client", capturedStackFrames = 5)

每当遇到此方法时,Instana 都将记录一个范围标记为“出口”调用。 出口标记对外部系统的出局呼叫。

退出和进入的相关性

在 Instana 尚不知道“出口”和“入口”的许多情况下,应用程序会使用它们来执行某种远程通信。 当遇到出口并且不执行任何关联时,跟踪将中断,这意味着将观察到两个跟踪,一个在出口处结束,另一个从入口处开始。

通过在远程通信中手动传输关联信息,可以帮助 Instana 执行关联。 在出口端,出口注释将确保存在必需的相关标识。 只需调用 ( https://github.com/instana/instana-java-sdk/blob/master/instana-java-sdk/src/main/java/com/instana/sdk/support/SpanSupport.java#L182 ):

SpanSupport.addTraceHeadersIfTracing(Type.EXIT, params);

以使用必需的标识填充给定的参数映射。 如果协议支持其他传输其他数据的方法,那么可以获取具有以下内容的标识:

currentTraceId(type)

currentSpanId(type)

在入口端,在通过注释创建范围之前,请务必读取参数并为入口范围设置这些参数:

(https://github.com/instana/instana-java-sdk/blob/master/instana-java-sdk-sample/custom-http-sample/src/main/java/com/instana/sample/GreetingHandler.java#L52):

SpanSupport.inheritNext(SpanSupport.stringAsId(trace), SpanSupport.stringAsId(span));

通过执行此操作,入口范围将自动加入远程跟踪并将其自身添加为调用出口的子范围。

转换和命名

在某些情况下,将 SDK 范围转换为其他类型(例如 HTTP 或 RPC)以更好地表示这些范围的来源可能是有益的。 可以通过向范围添加转换标记来完成此操作,如定制跟踪的最佳实践处理标记 部分中所述。

可以使用 SpanSupport.annotate(type, name, key, value) 方法来设置这些标记。

一旦这些字段嵌套在 tags. 键下,Instana 将以自动代理程序检测的方式处理这些标记。 所以,例如,要设置 http.url 字段,方法调用将如下所示:

SpanSupport.annotate(<type>, <name>, "tags.http.url", "service://my-awesome-service/some/path")

也可以采用相同的方式来更改服务、端点和调用名称,如定制跟踪的最佳实践页面中所述。

如果未提供任何特定字段,那么所有 SDK 范围的服务名称都将为 SDK。 在 @Span 注释或 SpanSupport.annotate() 方法中,端点和调用名称将为给定的 name

保存和恢复跟踪上下文

ContextSupport 类使您能够保存和恢复当前跟踪上下文。 takeSnapshot() 方法将跟踪上下文信息(例如,跟踪标识和范围标识)存储在内部映射中。 restoreSnapshot() 方法读取 takeSnapshot() 方法保存的信息,并使用该信息来设置当前跟踪上下文。 这些方法在应用程序使用异步处理来完成任务,并且需要在另一个线程中继续跟踪的情况下非常有用。

例如,可以使用以下命令保存当前跟踪上下文:

snapShotKey = ContextSupport.takeSnapshot();

然后,可以使用以下命令在另一个线程中复原跟踪上下文:

ContextSupport.restoreSnapshot(snapShotKey);

教程

以下教程将指导了解 Java Trace SDK 的一些常见用例:

故障诊断

如果 SDK 跟踪未显示在 UI 中,那么有几项需要检查:

  • instana-java-sdk JAR 是否随应用程序一起提供? 否则,代理程序将以静默方式不作任何操作,因为它处于 no-op 方式。
  • configuration.yaml文件引用所有带有注释的软件包 吗?
  • 跟踪是否处于活动状态?
  • YAML 语法是否正确?
  • 其他 APM 代理程序是否处于活动状态? 已知大多数其他 APM 代理程序会干扰 Instana,因此 Instana 的代理程序在检测到其他代理程序时不会执行跟踪。 如果是这种情况,那么将在日志中显示以下内容:
    JVM <PID> is running the <3rdParty> agent, which is known to be causing problems for the Instana Agent. Tracing will not be enabled for this JVM.
    
  • 打开 DEBUG 日志记录并查找类似如下的消息:
    2016-09-05T08:26:14.094+0200 | DEBUG | na-http-thread-1 | LoggerEndpoint                   | 48 - com.instana.agent - 1.1.194 | JVM (11403). Successfully instrumented class com.acme.resources.HelloWorldResource [sun.misc.Launcher$AppClassLoader@3d4eac69]`
    2016-09-05T08:26:14.145+0200 | DEBUG | na-http-thread-1 | LoggerEndpoint                   | 48 - com.instana.agent - 1.1.194 | JVM (11403) - Spent 188ms and 124kb transforming SDK classes. 
    
  • 用户/装入驱动程序是否实际命中已注释的方法? Instana 代理程序将在启动后立即与每个 JVM 进行交互。 因此,在连接代理程序之前发生的事务不会被捕获。 请确保对通常在应用程序生命周期内命中的方法进行注释。

常见问题解答

为什么捕获的参数和返回值只显示类名和散列内存地址?

检测将对每个捕获的参数和返回值调用 toString()。 这表示在 Instana 中可视的值直接取决于参数和返回值类的特定 toString() 方法实现。

如果未覆盖 toString(),那么最终将使用 java.lang.Object#toString()。 此方法返回 getClass().getName() + '@' + Integer.toHexString(hashCode()) 和您所看到的格式的结果。

要提高对已捕获参数和返回值的可视性,建议正确覆盖 toString()

为什么有时无法获得返回值?

即使设置了 captureReturn=true,返回值也可能不可用,当 ...

  • 该方法抛出了异常,
  • 方法具有 void 返回类型或当
  • 该方法返回 null