Tracing

This page walks you through how Tracing is used with Atoti Data Connectors and how to configure Tracing in your Atoti Server application.

Tracing Prerequisites

Atoti Data Connectors rely on Atoti Server’s APM (Application Performance Monitoring library) and a Tracing library to name and track internal operations and processes. For instance, the DLC will name a task based on a Tracer’s TraceId and all subsequent processes will also be tagged with the same TraceId but with a unique SpanId. TraceId and SpanIds are unique Hex strings, such as “7a8c982a87b050f2”.

Due to this reliance on Tracing, the ActivePivot APM module needs to be configured in your Atoti Server project. You can read Configuring APM in Atoti Server for details.

You will need to add a Tracing Configuration to your project. You can see an example below or implement your own by following the Atoti Server Tracing documentation.

Example Tracing Configuration

A spring Tracing Configuration has to be present in your ApplicationConfiguration.

Here is an example of a Tracing Configuration using Open Zipkin/Brave.

Dependencies for both APM and openzipkin/brave:

<!-- Tracing Dependencies -->

<!-- APM Dependencies -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-sleuth</artifactId>
	<version>${spring-sleuth.version}</version>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-sleuth-zipkin</artifactId>
	<version>${spring-sleuth.version}</version>
</dependency>

<!-- Brave used for APM -->
<dependency>
	<groupId>io.zipkin.brave</groupId>
	<artifactId>brave-instrumentation-spring-webmvc</artifactId>
	<version>${tracing.zipkin.brave.version}</version>
</dependency>

<!-- End of Tracing Dependencies -->

Brave Tracing Configuration Class

/**
 * Brave tracing configuration. 
 * 
 * This configuration is only enabled if Brave is included in the classpath.
 *
 * @author ActiveViam
 */
@Configuration
@ConditionalOnClass({Tracer.class})
public class BraveTracingConfig {

	@Bean
	public Tag<Throwable> errorTag() {
		return new Tag<>("error") {

			@Override
			protected String parseValue(Throwable input, TraceContext context) {
				return LoggingUtils.getMessageWithRootCauseDetail(input);
			}

		};
	}

	@Bean
	public Sampler defaultSampler() {
		return Sampler.ALWAYS_SAMPLE;
	}

	@Bean
	public ServletContextInitializer servletTracing() {
		return servletContext -> {
			// Enables tracing for servlet
			DelegatingTracingFilter filter = new DelegatingTracingFilter();
			String filterName = Conventions.getVariableName(filter);
			final FilterRegistration.Dynamic registration = servletContext.addFilter(filterName, filter);
			registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
		};
	}

}

Finally, add the BraveTracingConfig.class to your ApplicationConfig and APM will automatically use this Brave configuration.

How Tracing Is Used

What Is A TraceContext?

A TraceContext will be added to HealthEvents. This TraceContext object has a TraceId and SpanId property. The TraceContext is added to HealthEvents through the MonitoredHealthEventDispatcher. TraceContexts can be null if the APM Tracing has not properly been configured. When a DLC process is started, a Tracer is created. All processes started from within the DLC process are traced with the same TraceId. A TraceContext contains three values:

TraceContext Property Value
TraceId Globally unique ID. All tracers created under the parent tracer contain the same TraceId.
ParentId Parent tracer’s SpanId. This is the SpanId of the parent tracer.
SpanId Globally unique ID of the current process. Every time a new tracer is created (even under a parent), this value will be unique.

Example

Here’s an example of how the TraceContext is used and tracked through child processes.

In the image below, we have two DLC requests to execute in the DLC:

TraceContextDiagram

Each DLC request is given its own TaskTracer to trace all processes.

Every time a new sub-process is created, a child tracer is created under the current tracer. Here we can see how all tracers for a DLC request have the same TraceId. This is because all child tracers created from an existing tracer share the TraceId.

We can also see that all child tracers have a unique SpanId. The SpanId for the first tracer is the same as the TraceId - this is because this is the root tracer. Additionally all SpanId’s are used as child TraceContext’s Parent ID. With this information we can trace back an event to its parent and vice versa.