> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to set up Tracing with OpenTelemetry SDK

Atoti Server has been manually instrumented to provide precise and relevant feedback.
However, having the generated traces reach your chosen endpoint requires a bit of work.

In this example, we will write a Spring configuration that sets up the Atoti Server tracing to send traces to a local Zipkin instance.
The OpenTelemetry SDK will be used as our OpenTelemetry backend.

## Prerequisites

This guides is written with the assumption that a Zipkin server at the address `localhost:9411`. Readers can easily create such a server from Docker with a command similar to `docker run -d -p 9411:9411 openzipkin/zipkin`.

## Dependencies

We need the OpenTelemetry SDK, as well as a couple of necessary exporters.
Import the following dependencies:

```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-logging</artifactId>
</dependency>
```

## General structure

The tracing setup is a good fit for a Spring configuration class,
so that it can be swapped easily.
Create a Spring configuration, make sure it is imported by Spring, and start writing a Bean with the `OpenTelemetry` type.

## Creating the OpenTelemetry instance

An `OpenTelemetry` instance is made of three main parts: a tracer provider, a meter provider and a logger provider.
We need to instantiate each of those to create our OpenTelemetry instance.

### The Tracer Provider

For the tracer provider, we want it to export spans both to the console for debug purposes and to a Zipkin instance at the given URL.
We also add the service name resource to easily distinguish spans from Atoti Server from other spans the Zipkin instance may collect.

```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
String zipkinUrl = "http://localhost:9411/api/v2/spans";
SdkTracerProvider sdkTracerProvider =
    SdkTracerProvider.builder()
        .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create()))
        .addSpanProcessor(
            BatchSpanProcessor.builder(
                    ZipkinSpanExporter.builder().setEndpoint(zipkinUrl).build())
                .build())
        .addResource(
            Resource.create(
                Attributes.of(AttributeKey.stringKey("service.name"), "Atoti Server")))
        .build();
```

### The Meter Provider

The OpenTelemetry Metrics API isn't currently used by Atoti Server, so we use a placeholder meter provider,
that periodically prints metrics to the console:

```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
SdkMeterProvider sdkMeterProvider =
    SdkMeterProvider.builder()
        .registerMetricReader(
            PeriodicMetricReader.builder(LoggingMetricExporter.create()).build())
        .build();
```

### The Logger Provider

Similarly, this part of OpenTelemetry is unused for now, so we use a simple logger provider that redirects to the console.

```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
SdkLoggerProvider sdkLoggerProvider =
    SdkLoggerProvider.builder()
        .addLogRecordProcessor(
            SimpleLogRecordProcessor.create(SystemOutLogRecordExporter.create()))
        .build();
```

### Assembling the `OpenTelemetry` instance

Now that we have the main parts, we can construct the `OpenTelemetry` instance that we need.

```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
return OpenTelemetrySdk.builder()
    .setTracerProvider(sdkTracerProvider)
    .setMeterProvider(sdkMeterProvider)
    .setLoggerProvider(sdkLoggerProvider)
    .setPropagators(
        ContextPropagators.create(
            TextMapPropagator.composite(
                W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())))
    .build();
```

Use this as a bean in your application.

You should obtain a configuration class that should look quite like the `OpenTelemetryTracingConfig` from the sandbox.

## Wiring the `OpenTelemetry` instance

Now that the `OpenTelemetry` instance is finished, we have to provide it to the Atoti Server tracing framework.
Import the `TracingConfig` from our activepivot-server-spring module to take care of this step.
The `TracingConfig` will autowire the `OpenTelemetry` bean and provide it to the tracing framework.

## Check out the result

Everything is now setup to send application traces to Zipkin.<br />
Go to your AtotiUI application and create a new Pivot Table with some hierarchies and measures. You can see traces in Zipkin related to the queries.

## Going further

* There are alternative ways to wire the constructed `OpenTelemetry` instance detailed [here](./tracing#tracing-setup).
* There are many other OpenTelemetry exporters one may want to use, listed [there](https://opentelemetry.io/docs/instrumentation/java/exporters/).
