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.before
和testMethod11.after
的日志 -
如果抛出 exception,也会创建 log
testMethod11.afterFailure
-
将创建带有 key
testTag11
和 valuetest
的标记
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"
的标记。