Small question regarding a Java application, with Brave / Zipkin for traces please.
I have a very simple piece of code (code + maven pom attached, ready to run and reproduce the issue)
import io.netty.handler.logging.LogLevel;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.brave.ZipkinSpanHandler;
import zipkin2.reporter.urlconnection.URLConnectionSender;
import brave.Tracing;
import brave.opentracing.BraveTracer;
import java.util.Map;
public class QuestionApplication {
public static void main(String[] args) {
final var sender = URLConnectionSender.create("http://the-zipkin-instance.com:9411/api/v2/spans");
final var spanReporter = AsyncReporter.create(sender);
final var tracing = Tracing.newBuilder().localServiceName("thisIsTheClientApplicationWhoIsGeneratingTheFirstTraceId").addSpanHandler(ZipkinSpanHandler.create(spanReporter)).build();
final var tracer = BraveTracer.create(tracing).unwrap().tracer();
final var webClient = WebClient.create().mutate().clientConnector(new ReactorClientHttpConnector(HttpClient.create().wiretap("reactor.netty.http.client.HttpClient", LogLevel.INFO, AdvancedByteBufFormat.HEX_DUMP))).build();
final var jsonPayload = Map.of("key", "someKey", "value", "someValue");
final var span = tracer.currentSpan();
final var context = span.context();
final var traceIdString = context.traceIdString();
final var response = webClient.post().uri("http://the-server.com/api/route").header("X-B3-TraceId", traceIdString).body(BodyInserters.fromValue(jsonPayload)).retrieve().bodyToMono(String.class).block();
System.out.println(response);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github</groupId>
<artifactId>question</artifactId>
<version>1.1</version>
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-urlconnection</artifactId>
<version>2.16.3</version>
</dependency>
<dependency>
<groupId>io.opentracing.brave</groupId>
<artifactId>brave-opentracing</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
Here, with above code, I am getting a java.lang.NullPointerException
on line final var context = span.context();
because the span is null final var span = tracer.currentSpan();
This application is the "client" application, meaning the first to initiate the http call, hence, I would like this small piece of main code to be the first to generate the trace ID, which will travel within a dozen of other sub systems.
May I ask what is the issue, what is the root cause of this NPE, or should I say, what is the correct way to create this trace ID to be passed around as I am the first of the chain please?
Thank you
I don't know what your NPE generates (technically), but the SpanHandler injection and the Brave wrapper are weird, considering the Tracing is from Brave. Then the most likely thing is that in those two lines you are not injecting the necessary dependencies for the creation of Spans well.
Tracing.newBuilder().localServiceName("thisIsTheClientApplicationWhoIsGeneratingTheFirstTraceId").addSpanHandler(ZipkinSpanHandler.create(spanReporter)).build();
BraveTracer.create(tracing).unwrap().tracer();
Here I made an example without those lines and it works as you expected. With the parent-child flow structure, you can replicate and distribute it in its components by injecting and extracting the trace of the headers: X-B3-TraceId, X-B3-ParentSpanId, X-B3-SpanId, X-B3-Sampled.
main code
package com.stackoverflow.q69430794;
import brave.Span;
import brave.Tracing;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.okhttp3.OkHttpSender;
public class QuestionApplication {
public static void main(String[] args) {
var sender = OkHttpSender.newBuilder().endpoint("http://localhost:9411/api/v2/spans").build();
var reporter = AsyncReporter.builder(sender).build();
var tracing = Tracing.newBuilder().localServiceName("component-test").spanReporter(reporter).build();
// Create parent span and his child --------------------
// Parent
tracing.tracer().startScopedSpan("parentSpan");
Span span = tracing.tracer().currentSpan();
span.tag("key", "firstBiz");
// Child
tracing.tracer().startScopedSpanWithParent("childSpan", tracing.tracer().currentSpan().context());
Span childSpan = tracing.tracer().currentSpan();
childSpan.tag("key", "secondBiz");
childSpan.finish();
System.out.println("id:" + childSpan.context().traceIdString());
// Finish span
span.finish();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// -----------------------------------------------------
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.stackoverflow.q69430794</groupId>
<artifactId>69430794</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>69430794</name>
<description>Question # 69430794</description>
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave</artifactId>
<version>5.4.2</version>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-okhttp3</artifactId>
<version>2.7.9</version>
</dependency>
</dependencies>
</project>
I used docker image:
docker pull openzipkin/zipkin