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.before
和testMethod11.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"
的标记。