Spring Sleuth | Create fresh new (detached/orphaned) Trace - spring

I got a Spring Boot application making use of Spring Sleuth for tracing inter-service calls. Within that application a ScheduledExecutorService exists that performs http requests in a loop (pseudo-code below):
class HttpCaller implements Runnable {
public void run() {
performHttpCall();
// "loop"
executor.submit(this::run);
}
}
// start it once
scheduler.submit(new HttpCaller());
If I now have a look at the traces produced by Sleuth and stored in Zipkin I can see that all http calls are associated to a single Trace. Most likely because the trace context is handed over during the call to ScheduledExecutorService::submit.
How can I clear the current trace before starting the next iteration so that each http call will result in a new detached/orphaned trace?

If you're using Sleuth 2.0 you can call on the Tracer a method to create a new trace. In the older version of sleuth I guess what I'd do is to use an executor that is NOT a bean. That way you would lose the trace and it would get restarted at some point (by rest template or sth like that).

Related

Set custom traceId in spring sleuth

I have an angular application using a tracing library to trace each operation (user bouton click).
This application after SPA is loaded sends a list of traces in the request body to the backend microservice to log them.
In the backend microservice, I am using the spring boot 2.3.7, the spring cloud Hoxton.SR9 and logback 1.2.3.
This is the method:
#PostMapping("/traces")
public ResponseEntity<List<Trace>> addTrace(#RequestBody List<Trace> traces) {
traces.forEach(trace -> {
RtLog log = RtLog.builder.parentSpanId(trace.getParentId()).traceId(trace.getTraceId()).spanId(trace.getSpanId)).operationName(trace.getOperationName())
.businessJourney(trace.getBaggages().getBusinessJourney())
.componentId(trace.getBaggages().getComponentId()).componentType(trace.getBaggages().getComponentType())
.sessionId(trace.getBaggages().getSessionId()).userId(trace.getBaggages().getUserId())
.duration(trace.getDuration())
.time(!Null.isNullOrEmpty(datetime) ? datetime.format(DateTimeFormatter.ofPattern(TIMESTAMP_PATTERN))
: EMPTY)
.tags(trace.getTags()).build();
logger.info("spa_log", StructuredArguments.fields(log));
An example of traces send by the application:
The problem is when logging the information, the spring sleuth adds on the log another traceId and spanId that I don't need, and it causes conflict with the correct Ids.
So how can I override the traceId and spanId or is it possible to disable the tracing in this method?
There is the traceContext or brave Tracing but I found that I can builder a new trace but I didn't find a way to change the current trace.

How Do I Access The Spring Boot Startup Actuator During A Test

I would like to record the startup information about my application during a Spring Boot test. I have the startup actuator configured and working in Spring Boot 'bootrun' mode. However, when I try to access that actuator during a test using a TestRestTemplate, I get a 404 error.
I have written an example program that demonstrates the problem. The issue isn't with acutators overall as I have the metrics and health actuators working in the same test. Just the startup actuator.
The example code is on GitHub
I have a solution for this so I thought I would post it. For complete details, see the original repo in GitHub and check the solution branch.
One possible way to enable ApplicationStartup data collection during a Spring Boot Test is to create a ContextCustomizer. This allows you to get into the testing context early enough to record all of the data that you are looking for. The ContextCustomizer should have a single static BufferingApplicationStartup that it registers as a singleton bean into the test context's bean factory. It also needs to set the bean factory's ApplicationStartup because that will be passed to the SpringApplication just before it is run.
Here is the snippet of the customizer that holds the key:
#Override
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Object possibleSingleton = beanFactory.getSingleton(BEAN_NAME);
// The only way it wouldn't be an instance of a BufferingApplicationStartup is if it is null or we haven't
// run yet (and it is the DefaultApplicationStartup). In either case, jam our BufferingApplicationStartup
// in here.
if(!(possibleSingleton instanceof BufferingApplicationStartup)) {
beanFactory.registerSingleton(BEAN_NAME, APPLICATION_STARTUP);
beanFactory.setApplicationStartup(APPLICATION_STARTUP);
}
}
When you do this, make sure you implement a good equals and hashCode for your customizer or else you will break the test context caching and you will refresh your test context with every test class. Since the only relevant part of the customizer is the static BufferingApplicationStartup, I chose to return its hashcode.
Finally, don't forget to add your ContextCustomizerFactory to the src/test/resources/META-INF/spring.factories or else the rest of the Spring Boot testing support won't see your customizer.
Once this is all setup, you can access the Startup Actuator endpoint just like you would any other actuator.

Add sleuth trace id to request header

I have a spring boot application having dependency of spring-cloud-starter-sleuth-3.0.3 and spring-cloud-sleuth-zipkin-3.0.3.
I have a requirement that i need to pass trace-id to request header while calling API from webclient.
Demo webClient
#Slf4j
#Component
#RequiredArgsConstructor
public class DemoApiClient {
private final WebClient demoWebClient;
private final DemoProperties demoProperties;
private final Tracer tracer;
public Mono<DemoDetail> retrieveDemoDetail(String demo){
return demoWebClient
.get()
.uri(uriBuilder->uriBuilder
.path(demoProperties.getLookupPath())
.build(demo))
.header("trace-id", tracer.currentSpan().context().traceId())
.accept(APPLICATION_JSON)
.retrieve()
.bodyToMono(DemoDetail.class)
.doOnError(e -> log.error("Could not find demo", e));
}
}
tracer.currentSpan() is coming as null , hence NPE is thrown.
As per document, approach is given to add trace-id to header of response
https://docs.spring.io/spring-cloud-sleuth/docs/3.0.3/reference/html/howto.html#how-to-add-headers-to-the-http-server-response.
However, i need correct approach to add trace-id to request header.
WebClient is instrumented, please see the docs: WebClient integration, so tracing information should be propagated out of the box over the wire.
If you want to do this manually (I don't recommend), you need to check what you do "above" this method that prevents the tracing information to be propagated. E.g.: you are switching threads, coming from an imperative context to Reactor, etc. You can work this around by getting the tracing information before the switch and either propagate it (see Scope) or inject it into this method.
Also, you are not sending the whole trace context just the traceId so please check the docs and let Sleuth propagate the tracing information for you.
If you are creating a WebClient bean, you are not switching threads, or going back and forth between imperative and reactive, and you still don't see the tracing information in your header (propagated by Sleuth), you can try modifying the instrumentation mechanism, I recommend using DECORATE_QUEUES.
Also, Sleuth 3.1.x is out, you can try upgrading it.

Zipkin With Spring Boot

I am using spring boot and zipkin.
And using spring slueth to generate trace Id.
Is there a way I can generate this trace Id on my own?
Also I want to log only specific requests say with 500 error or response time > threshold, how to do this?
To log only request with particular error you can add the log in your exception mapper where you are handling those error.
To show the log for error response you can set like below,
#Autowired
private Tracer tracer;
and set
tracer.addTag("error","Your message")

Spring Boot 2 integrate Brave MySQL-Integration into Zipkin

I am trying to integrate the Brave MySql Instrumentation into my Spring Boot 2.x service to automatically let its interceptor enrich my traces with spans concerning MySql-Queries.
The current Gradle-Dependencies are the following
compile 'io.zipkin.zipkin2:zipkin:2.4.5'
compile('io.zipkin.reporter2:zipkin-sender-okhttp3:2.3.1')
compile('io.zipkin.brave:brave-instrumentation-mysql:4.14.3')
compile('org.springframework.cloud:spring-cloud-starter-zipkin:2.0.0.M5')
I already configured Sleuth successfully to send traces concerning HTTP-Request to my Zipkin-Server and now I wanted to add some spans for each MySql-Query the service does.
The TracingConfiguration it this:
#Configuration
public class TracingConfiguration {
/** Configuration for how to send spans to Zipkin */
#Bean
Sender sender() {
return OkHttpSender.create("https://myzipkinserver.com/api/v2/spans");
}
/** Configuration for how to buffer spans into messages for Zipkin */
#Bean AsyncReporter<Span> spanReporter() {
return AsyncReporter.create(sender());
}
#Bean Tracing tracing(Reporter<Span> spanListener) {
return Tracing.newBuilder()
.spanReporter(spanReporter())
.build();
}
}
The Query-Interceptor works properly, but my problem now is that the spans are not added to the existing trace but each are added to a new one.
I guess its because of the creation of a new sender/reporter in the configuration, but I have not been able to reuse the existing one created by the Spring Boot Autoconfiguration.
That would moreover remove the necessity to redundantly define the Zipkin-Url (because it is already defined for Zipkin in my application.yml).
I already tried autowiring the Zipkin-Reporter to my Bean, but all I got is a SpanReporter - but the Brave-Tracer-Builder requries a Reporter<Span>
Do you have any advice for me how to properly wire things up?
Please use latest snapshots. Sleuth in latest snapshots uses brave internally so integration will be extremely simple.

Resources