58. 使用 Annotations 管理 Spans

您可以使用各种注释管理 spans。

58.1 基本原理

使用 annotations 管理 spans 有很多很好的理由,包括:

  • API-agnostic 表示与 span 合作。使用 annotations 可以让用户在 span api 上添加没有 library 依赖的 span。这样做可以让 Sleuth 更改其核心 API,从而减少对用户 code 的影响。

  • 减少了基本 span 操作的表面积。如果没有此 feature,则必须使用 span api,它具有可能无法正确使用的生命周期命令。通过仅公开范围,标记和 log 功能,您可以进行协作,而不会意外地破坏 span 生命周期。

  • 与运行时协作生成 code。使用诸如 Spring Data 和 Feign 之类的 libraries,接口的 implementation 在运行时生成。因此,span 包裹 objects 是乏味的。现在,您可以通过接口和这些接口的 arguments 提供 annotations。

58.2 创造新的 Spans

如果您不想手动创建本地 spans,则可以使用@NewSpan annotation。此外,我们提供@SpanTag annotation 以自动方式添加标签。

现在我们可以考虑一些使用示例。

@NewSpan
void testMethod();

在没有任何参数的情况下注释该方法会导致 creating 一个新的 span,其 name 等于带注释的方法 name。

@NewSpan("customNameOnTestMethod4")
void testMethod4();

如果在 annotation 中提供 value(直接或通过设置name参数),则创建的 span 将提供的 value 作为 name。

// method declaration
@NewSpan(name = "customNameOnTestMethod5")
void testMethod5(@SpanTag("testTag") String param);

// and method execution
this.testBean.testMethod5("test");

您可以将 name 和标记结合使用。让我们关注后者。在这种情况下,带注释的方法的参数 runtime value 的 value 将成为标记的 value。在我们的 sample 中,标签 key 是testTag,标签 value 是test

@NewSpan(name = "customNameOnTestMethod3")
@Override
public void testMethod3() {
}

您可以将@NewSpan annotation 放在 class 和接口上。如果覆盖接口的方法并为@NewSpan annotation 提供不同的 value,则最具体的一个获胜(在这种情况下设置为customNameOnTestMethod3)。

58.3 继续 Spans

如果要向现有的 span 添加标签和 annotations,可以使用@ContinueSpan annotation,如下面的示例所示:

// method declaration
@ContinueSpan(log = "testMethod11")
void testMethod11(@SpanTag("testTag11") String param);

// method execution
this.testBean.testMethod11("test");
this.testBean.testMethod13();

(注意,与@NewSpan annotation 相比,您还可以使用log parameter.)添加日志

这样,span 继续下去:

  • 创建名为testMethod11.beforetestMethod11.after的日志条目。

  • 如果抛出 exception,则还会创建名为testMethod11.afterFailure的 log 条目。

  • 创建 key 为testTag11且 value 为test的标记。

58.4 高级标签设置

有三种不同的方法可以向 span 添加标签。所有这些都由SpanTag annotation 控制。优先顺序如下:

  • 尝试使用TagValueResolver类型的 bean 和提供的 name。

  • 如果尚未提供 bean name,请尝试计算表达式。我们搜索TagValueExpressionResolver bean。默认 implementation 使用 SPEL 表达式解析。 重要您只能从 SPEL 表达式 reference properties。由于安全性限制,不允许执行方法。

  • 如果我们找不到要评估的表达式,_return 参数的toString() value。

58.4.1 自定义提取器

以下方法的标记的 value 由TagValueResolver接口的 implementation 计算。它的 class name 必须作为resolver属性的 value 传递。

请考虑以下带注释的方法:

@NewSpan
public void getAnnotationForTagValueResolver(@SpanTag(key = "test", resolver = TagValueResolver.class) String test) {
}

现在进一步考虑以下TagValueResolver bean implementation:

@Bean(name = "myCustomTagValueResolver")
public TagValueResolver tagValueResolver() {
	return parameter -> "Value from myCustomTagValueResolver";
}

前面两个示例导致将标签 value 设置为等于Value from myCustomTagValueResolver

58.4.2 解析 Value 的表达式

请考虑以下带注释的方法:

@NewSpan
public void getAnnotationForTagValueExpression(@SpanTag(key = "test", expression = "'hello' + ' characters'") String test) {
}

没有TagValueExpressionResolver的自定义_impleration 导致 SPEL 表达式的 evaluation,并且 span 上设置了 value 为4 characters的标记。如果要使用其他一些表达式解析机制,可以创建自己的 bean 实现 bean。

58.4.3 使用 toString()方法

请考虑以下带注释的方法:

@NewSpan
public void getAnnotationForArgumentToString(@SpanTag("test") Long param) {
}

使用_val运行上述方法会导致设置 String value 为"15"的标记。