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)
在入口端,在通过注释创建范围之前,请务必读取参数并为入口范围设置这些参数:
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-sdkJAR 是否随应用程序一起提供? 否则,代理程序将以静默方式不作任何操作,因为它处于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。