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

mp.telemetry.adoc Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2023, 2024 Oracle and/or its affiliates.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

///////////////////////////////////////////////////////////////////////////////

= Telemetry
:description: Helidon MP Telemetry Support
:feature-name: MicroProfile Telemetry
:keywords: helidon, telemetry, microprofile, micro-profile
:microprofile-bundle: true
:rootdir: {docdir}/..
:mp-telemetry-version: 1.1
:otel-version: 1.29.0

include::{rootdir}/includes/mp.adoc[]

== Contents

- <>
- <>
- <>
- <>
- <>
- <>

== Overview

include::{rootdir}/includes/dependencies.adoc[]

[source,xml]
----

    io.helidon.microprofile.telemetry
    helidon-microprofile-telemetry

----

== Usage

link:https://opentelemetry.io/[OpenTelemetry] comprises a collection of APIs, SDKs, integration tools, and other software components intended to facilitate the generation and control of telemetry data, including traces, metrics, and logs. In an environment where distributed tracing is enabled via OpenTelemetry (which combines OpenTracing and OpenCensus), this specification establishes the necessary behaviors for MicroProfile applications to participate seamlessly.

MicroProfile Telemetry {mp-telemetry-version} allows for the exportation of the data it collects to Jaeger or Zipkin and to other systems using a variety of exporters.

// @Deprecated(forRemoval = true) In 5.x remove the following note.
[NOTE]
.Span Names for REST Requests
====
If possible, assign the following config setting in your application's `META-INF/microprofile-config.properties` file:
[source,properties]
----
mp.telemetry.span.name-includes-method = true
----
Earlier releases of Helidon 4 implemented MicroProfile Telemetry 1.0 which was based on OpenTelemetry semantic conventions 1.22.0-alpha.

MicroProfile Telemetry {mp-telemetry-version} is based on OpenTelemetry {otel-version}, and in that release the semantic convention for the REST span name now includes the HTTPmethod name, as shown in the format below.
[source]
----
{http-method-name} {http-request-route}
----
(see https://opentelemetry.io/docs/specs/semconv/http/http-spans/#name)

Although span names are often used only for display in monitoring tools, this is a backward-incompatible change.

Therefore, Helidon {helidon-version} by default conforms to the _older_ semantic convention to preserve backward compatibility with earlier 4.x releases. Only if you set the property as shown above will Helidon {helidon-version} use the new span naming format.

The ability to use the older format is deprecated, and you should plan for its removal in a future major release of Helidon. For that reason Helidon logs a warning message if you use the older REST span naming convention.
====
// end of text to be removed in 5.x

In a distributed tracing system, *traces* are used to capture a series of requests and are composed of multiple *spans* that represent individual operations within those requests. Each *span* includes a name, timestamps, and metadata that provide insights into the corresponding operation.

*Context* is included in each span to identify the specific request that it belongs to. This context information is crucial for tracking requests across various components in a distributed system, enabling developers to trace a single request as it traverses through multiple services.

Finally, *exporters* are responsible for transmitting the collected trace data to a backend service for monitoring and visualization. This enables developers to gain a comprehensive understanding of the system's behavior and detect any issues or bottlenecks that may arise.

image::telemetry/telemetry-general.png[General understanding of OpenTelemetry Tracing,role="fit"]

There are two ways to work with Telemetry, using:

- Automatic Instrumentation
- Manual Instrumentation

For Automatic Instrumentation, OpenTelemetry provides a JavaAgent. The Tracing API allows for the automatic participation in distributed tracing of Jakarta RESTful Web Services (both server and client) as well as MicroProfile REST Clients, without requiring any modifications to the code. This is achieved through automatic instrumentation.

For Manual Instrumentation, there is a set of annotations and access to OpenTelemetry API.

`@WithSpan` - By adding this annotation to a method in any Jakarta CDI aware bean, a new span will be created and any necessary connections to the current Trace context will be established. Additionally, the `SpanAttribute` annotation can be used to mark method parameters that should be included in the Trace.

Helidon provides full access to OpenTelemetry Tracing API:

* `io.opentelemetry.api.OpenTelemetry`
* `io.opentelemetry.api.trace.Tracer`
* `io.opentelemetry.api.trace.Span`
* `io.opentelemetry.api.baggage.Baggage`

Accessing and using these objects can be done as follows. For span:

.Span sample
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_1, indent=0]
----
<1> Simple `@WithSpan` annotation usage.
<2> Additional attributes can be set on a method.


=== Working With Tracers

You can inject OpenTelemetry `Tracer` using the regular `@Inject` annotation and use `SpanBuilder` to manually create, star and stop spans.

.SpanBuilder usage
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_2, indent=0]
----
<1> Inject `Tracer`.
<2> Use `Tracer.spanBuilder` to create and start new `Span`.

Helidon Microprofile Telemetry is integrated with xref:tracing.adoc[Helidon Tracing API]. This means that both APIs can be mixed, and all parent hierarchies will be kept. In the case below, `@WithSpan` annotated method is mixed with manually created `io.helidon.tracing.Span`:

.Inject Helidon Tracer
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_3, indent=0]
----
<1> Inject `io.helidon.tracing.Tracer`.
<2> Use the injected tracer to create  `io.helidon.tracing.Span` using the `spanBuilder()` method.

The span is then started and ended manually. Span parent relations will be preserved. This means that span named "mixed_injected" with have parent span named "mixed_parent_injected", which will have parent span named "mixed_injected".

Another option is to use the Global Tracer:

.Obtain the Global tracer
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_4, indent=0]
----
<1> Obtain tracer using the `io.helidon.tracing.Tracer.global()` method;
<2> Use the created tracer to create a span.

The span is then started and ended manually. Span parent relations will be preserved.


=== Working With Spans

To obtain the current span, it can be injected by CDI. The current span can also be obtained using the static method `Span.current()`.

.Inject the current span
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_5, indent=0]
----
<1> Inject the current span.
<2> Use the injected span.
<3> Use `Span.current()` to access the current span.

=== Working With Baggage

The same functionality is available for the `Baggage` API:

.Inject the current baggage
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_6, indent=0]
----
<1> Inject the current baggage.
<2> Use the injected baggage.
<3> Use `Baggage.current()` to access the current baggage.

include::{rootdir}/includes/tracing/common-callbacks.adoc[tags=defs;detailed,leveloffset=+1]

== Configuration

IMPORTANT: MicroProfile Telemetry is not activated by default. To activate this feature, you need to specify the configuration `otel.sdk.disabled=false` in one of the MicroProfile Config or other config sources.

To configure OpenTelemetry, MicroProfile Config must be used, and the configuration properties outlined in the following sections must be followed:

- link:https://github.com/open-telemetry/opentelemetry-java/tree/v1.19.0/sdk-extensions/autoconfigure[OpenTelemetry SDK Autoconfigure] (excluding properties related to Metrics and Logging)
- link:https://opentelemetry.io/docs/instrumentation/java/manual/[Manual Instrumentation]

Please consult with the links above for all configurations' properties usage.

The property should be declared in `microprofile-config.properties` file to be processed correctly.


=== OpenTelemetry Java Agent

The OpenTelemetry Java Agent may influence the work of MicroProfile Telemetry, on how the objects are created and configured. Helidon will do "best effort" to detect the use of the agent. But if there is a decision to run the Helidon app with the agent, a configuration property should be set:

`otel.agent.present=true`

This way, Helidon will explicitly get all the configuration and objects from the Agent, thus allowing correct span hierarchy settings.

== Examples

This guide demonstrates how to incorporate MicroProfile Telemetry into Helidon and provides illustrations of how to view traces. Jaeger is employed in all the examples, and the Jaeger UI is used to view the traces.

=== Set Up Jaeger

For example, Jaeger will be used for gathering of the tracing information.

.Run Jaeger in a docker container.
[source, bash]
----
docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -e COLLECTOR_OTLP_ENABLED=true \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 14250:14250 \
  -p 14268:14268 \
  -p 14269:14269 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.50
----

All the tracing information gathered from the examples runs is accessible from the browser in the Jaeger UI under link:http://localhost:16686/[]

=== Enable MicroProfile Telemetry in Helidon Application

Together with Helidon Telemetry dependency, an OpenTelemetry Exporter dependency should be added to project's pom.xml file.

[source,xml]
----

    
        io.helidon.microprofile.telemetry
        helidon-microprofile-telemetry 
    
    
        io.opentelemetry
        opentelemetry-exporter-jaeger  
    

----
<1> Helidon Telemetry dependency.
<2> OpenTelemetry Jaeger exporter.

Add these lines to `META-INF/microprofile-config.properties`:

.MicroProfile Telemetry properties
[source,properties]
----
otel.sdk.disabled=false     <1>
otel.traces.exporter=jaeger <2>
otel.exporter.name=greeting-service <3>
----
<1> Enable MicroProfile Telemetry.
<2> Set exporter to Jaeger.
<3> Name of our service.

Here we enable MicroProfile Telemetry, set tracer to "jaeger" and give a name, which will be used to identify our service in the tracer.

[NOTE]
====

For this example, you will use Jaeger to manage data tracing. If you prefer to use Zipkin, please set `otel.traces.exporter` property to "zipkin". For more information using about Zipkin, see link:https://zipkin.io/[]. Also, a corresponding Maven dependency for the exporter should be added:
----

    io.opentelemetry
    opentelemetry-exporter-zipkin

----
====


=== Tracing at Method Level

To create simple services, use `@WithSpan` and `Tracer` to create span and let MicroProfile OpenTelemetry handle them.

[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_7, indent=0]
----
<1> Use of `@WithSpan` with name "default".

Now let's call the Greeting endpoint:

[source,bash]
----
curl localhost:8080/greet
Hello World
----

Next, launch the Jaeger UI at link:http://localhost:16686/[]. The expected output is:

image::telemetry/telemetry-greeting-jaeger.png[Greeting service tracing output,role="fit"]

.Custom method
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_8, indent=0]
----
<1> Inject OpenTelemetry `Tracer`.
<2> Create a span around the method `useCustomSpan()`.
<3> Create a custom `INTERNAL` span and start it.
<4> End the custom span.

Let us call the custom endpoint:

[source,bash]
----
curl localhost:8080/greeting/custom
----

Again you can launch the Jaeger UI at link:http://localhost:16686/[]. The expected output is:

image::telemetry/telemetry-custom-jaeger.png[Custom span usage,role="fit"]

Now let us use multiple services calls. In the example below our main service will call the `secondary` services. Each method in each service will be annotated with `@WithSpan` annotation.

.Outbound method
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_9, indent=0]
----
<1> Inject `WebTarget` pointing to Secondary service.
<2> Wrap method using `WithSpan`.
<3> Call the secondary service.

The secondary service is basic; it has only one method, which is also annotated with `@WithSpan`.

.Secondary service
[source,java]
----
include::{sourcedir}/mp/TelemetrySnippets.java[tag=snippet_10, indent=0]
----
<1> Wrap method in a span.
<2> Return a string.

Let us call the _Outbound_ endpoint:

[source,bash]
----
curl localhost:8080/greet/outbound
Secondary
----

The `greeting-service` call `secondary-service`. Each service will create spans with corresponding names, and a service class hierarchy will be created.

Launch the Jaeger UI at link:http://localhost:16686/[] to see the expected output (shown below).

image::telemetry/telemetry-outbound-jaeger.png[Secondary service outbound call,role="fit"]

This example is available at the link:{helidon-github-examples-url}/microprofile/telemetry[Helidon official GitHub repository].

== Reference

* link:https://download.eclipse.org/microprofile/microprofile-telemetry-{mp-telemetry-version}/tracing/microprofile-telemetry-tracing-spec-{mp-telemetry-version}.pdf[MicroProfile Telemetry Specification]
* link:https://opentelemetry.io/docs/[OpenTelemetry Documentation]




© 2015 - 2024 Weber Informatics LLC | Privacy Policy