Small question regarding a Java 11 + SpringBoot 2.6.7 web application, in the context of Zipkin please.
I have a very simple micro services architecture SpringBoot repo that can be found here: https://github.com/dogukankrtlz/springboot-sleuth-zipkin, please feel free to clone.
Here are the relevant code for each micro service, it is very straightforward, I omitted the POJOs etc...
Main service, called customer service, is calling to call two child services:
@RequestMapping(value="/customer/{cid}", method=RequestMethod.GET)
public CustomerDetails getCustomer(@PathVariable String cid) {
CustomerDetails customer = new CustomerDetails();
ContactDetails svc1 = wc.get()
.uri("http://localhost:8081/customer/" + cid + "/contactdetails")
.retrieve()
.bodyToMono(ContactDetails.class)
.block();
VehicleDetails svc2 = wc.get()
.uri("http://localhost:8082/customer/" + cid + "/vehicledetails")
.retrieve()
.bodyToMono(VehicleDetails.class)
.block();
customer.setContactId(cid);
customer.setContactName(svc1.getContactName());
customer.setPostalCode(svc1.getPostalCode());
customer.setLicensePlate(svc2.getLicensePlate());
customer.setCarType(svc2.getCarType());
return customer;
}
Calling service A
@RequestMapping(value="/customer/{cid}/contactdetails", method= RequestMethod.GET)
public ContactDetails getCustomerContactDetails(@PathVariable String cid) throws InterruptedException {
Span dbSpan = this.tracer.nextSpan().name("DBLookup");
try (Tracer.SpanInScope ws = this.tracer.withSpan(dbSpan.start())) {
dbSpan.tag("call", "sql-database");
Random r = new Random();
int multiplier = r.nextInt(5) * 1000;
Thread.sleep(multiplier);
dbSpan.event("db lookup complete");
}
finally {
dbSpan.end();
}
return details.stream().filter(detail -> cid.equals(detail.getContactId())).findAny().orElse(null);
}
Then calling service B
@RequestMapping(value="/customer/{cid}/vehicledetails", method=RequestMethod.GET)
public VehicleDetails getCustomerVehicleDetails(@PathVariable String cid) {
return details.stream().filter(detail -> cid.equals(detail.getCustomerId())).findAny().orElse(null);
}
Once I make a request, I can see in the logs the traces, things are working, happy:
DEBUG [customerservice,25ef30dd73fbb6d8,25ef30dd73fbb6d8] 26578 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
DEBUG [dataservice1,25ef30dd73fbb6d8,65be0bf2df917b35] 26576 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
DEBUG [dataservice2,25ef30dd73fbb6d8,a490771db3881b76] 26570 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
Please note, I can see all trace IDs fine: 25ef30dd73fbb6d8,25ef30dd73fbb6d8 on the Main service, 25ef30dd73fbb6d8,65be0bf2df917b35 and 25ef30dd73fbb6d8,a490771db3881b76 on child services.
Most important part, I can even see the traces in Zipkin Server, they are all here, beautiful, will all relevant information: (see screenshot)
Things are working quite well, so far. Now, I would like to add a client. This is where things start to go south.
I add this client, also very straightforward:
public static void main(String[] args) {
final OkHttpSender sender = OkHttpSender.newBuilder().endpoint("http://localhost:9411/api/v2/spans").build();
final AsyncReporter<Span> reporter = AsyncReporter.create(sender);
final Tracing tracing = Tracing.newBuilder().localServiceName("ClientService").addSpanHandler(ZipkinSpanHandler.create(reporter)).build();
final BraveTracer tracer = BraveTracer.create(tracing);
final BraveSpan parent = tracer.buildSpan("client start API").start();
final WebClient webClient = WebClient.create().mutate().defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE, HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).clientConnector(new ReactorClientHttpConnector(HttpClient.create().responseTimeout(Duration.ofSeconds(10)).wiretap(true).protocol(HttpProtocol.HTTP11))).build();
final String response = webClient.get().uri("http://localhost:8080/customer/500").header("X-B3-TraceId", parent.unwrap().context().traceIdString()).header("X-B3-SpanId", parent.unwrap().context().spanIdString()).retrieve().bodyToMono(String.class).onErrorReturn("ERROR").block();
parent.finish();
reporter.flush();
System.out.println("->" + response);
}
I do see logs from both client and server:
client: X-B3-TraceId: d96d2354f60b306a..X-B3-SpanId: d96d2354f60b306a
server:
DEBUG [customerservice,d96d2354f60b306a,d96d2354f60b306a]
DEBUG [dataservice1,d96d2354f60b306a,f61a595dfd045e17]
DEBUG [dataservice2,d96d2354f60b306a,df125c7d44c5143c]
I go back into Zipkin with hope, and this is all I see:
What I would expect to see, is definitely something more like this (photoshop).
May I ask what went wrong here?
How to achieve a result where I can see the complete trace, from client all the way to server, all in one place in Zipkin?
Thank you