53. 使用 annotations 管理 spans

53.1 基本原理

这个 features 的主要 arguments 是

  • api-agnostic 表示与 span 合作

  • 使用 annotations 允许用户添加到 span api 上没有 library 依赖的 span。这允许 Sleuth 更改其核心 api,减少对用户 code 的影响。

  • 减少了基本 span 操作的表面积。

  • 没有这个 feature,必须使用 span api,它具有可能被错误使用的生命周期命令。通过仅公开范围,标记和 log 功能,用户可以协作而不会意外地破坏 span 生命周期。

  • 与运行时协作生成 code

  • 使用 libraries,例如 Spring Data/Feign,接口的 implementations 在运行时生成,因此_spject 包裹 objects 是乏味的。现在,您可以通过这些接口的接口和 arguments 提供 annotations

53.2 创造新的 spans

如果你真的不想手动 creating 本地 spans,你可以从@NewSpan annotation 中获益。我们还为您提供@SpanTag annotation 以自动方式添加标签。

我们来看一些使用示例。

@NewSpan
void testMethod();

在没有任何参数的情况下对方法进行注释将导致创建一个新的 span,其 name 将等于带注释的方法 name。

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

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

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

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

您可以将 name 和标记结合使用。让我们关注后者。在这种情况下,无论注释方法的参数运行时 value 的 value 是什么 - 将是标记的 value。在我们的 sample 中,标签 key 将为testTag,标签 value 将为test

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

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

53.3 继续 spans

如果您只想将标签和注释添加到现有的 span 中,则足以使用@ContinueSpan annotation,如下所示。请注意,与@NewSpan annotation 相比,您还可以通过log参数添加日志:

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

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

这样,span 将继续下去:

  • 将创建 name testMethod11.beforetestMethod11.after的日志

  • 如果抛出 exception,也会创建 log testMethod11.afterFailure

  • 将创建带有 key testTag11和 value test的标记

53.4 更高级的标签设置

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

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

  • 如果没有提供 bean name,请尝试计算表达式。我们正在搜索TagValueExpressionResolver bean。默认 implementation 使用 SPEL 表达式解析。如果我们找不到要评估的表达式,_return 参数的toString() value。 重要您只能从 SPEL 表达式 reference properties。由于安全性限制,不允许执行方法。

  • 如果没有提供任何表达式来评估 return 参数的toString() value

53.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

53.4.2 解析 value 的表达式

有这样一个带注释的方法:

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

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

53.4.3 使用 toString 方法

有这样一个带注释的方法:

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

如果使用_val执行将导致设置 String value 为"15"的标记。