All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mework.cloud.spring-cloud-sleuth-docs.3.1.7.source-code.using.adoc Maven / Gradle / Ivy

[[using]]
= Using Spring Cloud Sleuth

include::_attributes.adoc[]

This section goes into more detail about how you should use {project-full-name}.
It covers topics such as controlling the span lifecycle with {project-full-name} API or via annotations.
We also cover some {project-full-name} best practices.

If you are starting out with {project-full-name}, you should probably read the
<> guide before diving into this section.

[[using-span-lifecycle]]
== Span Lifecycle with Spring Cloud Sleuth's API

Spring Cloud Sleuth Core in its `api` module contains all necessary interfaces to be implemented by a tracer.
The project comes with OpenZipkin Brave implementation.
You can check how the tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge`.

The most commonly used interfaces are:

* `org.springframework.cloud.sleuth.Tracer` - Using a tracer, you can create a root span capturing the critical path of a request.
* `org.springframework.cloud.sleuth.Span` - Span is a single unit of work that needs to be started and stopped.
Contains timing information and events and tags.

You can also use your tracer implementation's API directly.

Let's look at the following Span lifecycle actions.

* <>: When you start a span, its name is assigned and the start timestamp is recorded.
* <>: The span gets finished (the end time of the span is recorded) and, if the span is sampled, it is eligible for collection (e.g. to Zipkin).
* <>: The span gets continued e.g. in another thread.
* <>: You can create a new span and set an explicit parent for it.

TIP: Spring Cloud Sleuth creates an instance of `Tracer` for you.
In order to use it, you can autowire it.

[[using-creating-and-ending-spans]]
=== Creating and Ending Spans

You can manually create spans by using the `Tracer`, as shown in the following example:

[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=manual_span_creation,indent=0]
----

In the preceding example, we could see how to create a new instance of the span.
If there is already a span in this thread, it becomes the parent of the new span.

IMPORTANT: Always clean after you create a span.

IMPORTANT: If your span contains a name greater than 50 chars, that name is truncated to 50 chars.
Your names have to be explicit and concrete.
Big names lead to latency issues and sometimes even exceptions.

[[using-continuing-spans]]
=== Continuing Spans

Sometimes, you do not want to create a new span but you want to continue one.
An example of such a situation might be as follows:

* *AOP*: If there was already a span created before an aspect was reached, you might not want to create a new span.

To continue a span, you can store the span in one thread and pass it on to another one as shown in the example below.

[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=manual_span_continuation,indent=0]
----

[[using-creating-spans-with-explicit-parent]]
=== Creating a Span with an explicit Parent

You might want to start a new span and provide an explicit parent of that span.
Assume that the parent of a span is in one thread and you want to start a new span in another thread.
Whenever you call `Tracer.nextSpan()`, it creates a span in reference to the span that is currently in scope.
You can put the span in scope and then call `Tracer.nextSpan()`, as shown in the following example:

[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=manual_span_joining,indent=0]
----

IMPORTANT: After creating such a span, you must finish it.
Otherwise it is not reported (e.g. to Zipkin).

You can also use the `Tracer.nextSpan(Span parentSpan)` version to provide the parent span explicitly.

[[using-naming-spans]]
== Naming Spans

Picking a span name is not a trivial task.
A span name should depict an operation name.
The name should be low cardinality, so it should not include identifiers.

Since there is a lot of instrumentation going on, some span names are artificial:

* `controller-method-name` when received by a Controller with a method name of `controllerMethodName`
* `async` for asynchronous operations done with wrapped `Callable` and `Runnable` interfaces.
* Methods annotated with `@Scheduled` return the simple name of the class.

Fortunately, for asynchronous processing, you can provide explicit naming.

[[using-naming-spans-annotation]]
=== `@SpanName` Annotation

You can name the span explicitly by using the `@SpanName` annotation, as shown in the following example:

[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=span_name_annotation,indent=0]
----

In this case, when processed in the following manner, the span is named `calculateTax`:

[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=span_name_annotated_runnable_execution,indent=0]
----

[[using-naming-spans-to-string]]
=== `toString()` Method

It is pretty rare to create separate classes for `Runnable` or `Callable`.
Typically, one creates an anonymous instance of those classes.
You cannot annotate such classes.
To overcome that limitation, if there is no `@SpanName` annotation present, we check whether the class has a custom implementation of the `toString()` method.

Running such code leads to creating a span named `calculateTax`, as shown in the following example:

[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=span_name_to_string_runnable_execution,indent=0]
----

[[using-annotations]]
== Managing Spans with Annotations

There are a number of good reasons to manage spans with annotations, including:

* API-agnostic means to collaborate with a span.
Use of annotations lets users add to a span with no library dependency on a span api.
Doing so lets Sleuth change its core API to create less impact to user code.
* Reduced surface area for basic span operations.
Without this feature, you must use the span api, which has lifecycle commands that could be used incorrectly.
By only exposing scope, tag, and log functionality, you can collaborate without accidentally breaking span lifecycle.
* Collaboration with runtime generated code.
With libraries such as Spring Data and Feign, the implementations of interfaces are generated at runtime.
Consequently, span wrapping of objects was tedious.
Now you can provide annotations over interfaces and the arguments of those interfaces.

[[using-annotations-new-spans]]
=== Creating New Spans

If you do not want to create local spans manually, you can use the `@NewSpan` annotation.
Also, we provide the `@SpanTag` annotation to add tags in an automated fashion.

Now we can consider some examples of usage.

[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=annotated_method,indent=0]
----

Annotating the method without any parameter leads to creating a new span whose name equals the annotated method name.

[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=custom_name_on_annotated_method,indent=0]
----

If you provide the value in the annotation (either directly or by setting the `name` parameter), the created span has the provided value as the name.

[source,java,indent=0]
----
// method declaration
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=custom_name_and_tag_on_annotated_method,indent=0]

// and method execution
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=execution,indent=0]
----

You can combine both the name and a tag.
Let's focus on the latter.
In this case, the value of the annotated method's parameter runtime value becomes the value of the tag.
In our sample, the tag key is `testTag`, and the tag value is `test`.

[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=name_on_implementation,indent=0]
----

You can place the `@NewSpan` annotation on both the class and an interface.
If you override the interface's method and provide a different value for the `@NewSpan` annotation, the most concrete one wins (in this case `customNameOnTestMethod3` is set).

[[using-annotations-continuing-spans]]
=== Continuing Spans

If you want to add tags and annotations to an existing span, you can use the `@ContinueSpan` annotation, as shown in the following example:

[source,java,indent=0]
----
// method declaration
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=continue_span,indent=0]

// method execution
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=continue_span_execution,indent=0]
----

(Note that, in contrast with the `@NewSpan` annotation ,you can also add logs with the `log` parameter.)

That way, the span gets continued and:

* Log entries named `testMethod11.before` and `testMethod11.after` are created.
* If an exception is thrown, a log entry named `testMethod11.afterFailure` is also created.
* A tag with a key of `testTag11` and a value of `test` is created.

[[using-annotations-advanced-tag-setting]]
=== Advanced Tag Setting

There are 3 different ways to add tags to a span.
All of them are controlled by the `SpanTag` annotation.
The precedence is as follows:

. Try with a bean of `TagValueResolver` type and a provided name.
. If the bean name has not been provided, try to evaluate an expression.
We search for a `TagValueExpressionResolver` bean.
The default implementation uses SPEL expression resolution.
**IMPORTANT** You can only reference properties from the SPEL expression.
Method execution is not allowed due to security constraints.
. If we do not find any expression to evaluate, return the `toString()` value of the parameter.

[[using-annotations-custom-extractor]]
==== Custom Extractor

The value of the tag for the following method is computed by an implementation of `TagValueResolver` interface.
Its class name has to be passed as the value of the `resolver` attribute.

Consider the following annotated method:

[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=resolver_bean,indent=0]
----

Now further consider the following `TagValueResolver` bean implementation:

[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=custom_resolver,indent=0]
----

The two preceding examples lead to setting a tag value equal to `Value from myCustomTagValueResolver`.

[[using-annotations-resolving-expressions]]
==== Resolving Expressions for a Value

Consider the following annotated method:

[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=spel,indent=0]
----

No custom implementation of a `TagValueExpressionResolver` leads to evaluation of the SPEL expression, and a tag with a value of `hello characters` is set on the span.
If you want to use some other expression resolution mechanism, you can create your own implementation of the bean.

[[using-annotations-to-string]]
==== Using The `toString()` Method

Consider the following annotated method:

[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=toString,indent=0]
----

Running the preceding method with a value of `15` leads to setting a tag with a String value of `"15"`.

[[using-whats-next]]
== What to Read Next

You should now understand how you can use {project-full-name} and some best practices that you should follow.
You can now go on to learn about specific
<>, or you could skip ahead and read about the link:integrations[integrations available in {project-full-name}].




© 2015 - 2024 Weber Informatics LLC | Privacy Policy