The problem occurs when Spring Integration(spring boot) Application calls Spring boot application for sleuth logging of traceID and spanID from.
URL call --> Facade(written in spring integration,spring boot and supports sleuth)--> Spring boot microservice(Sleuth supported)
Microservice 1 : spring integration Http call
Microservice 2 : spring boot Rest controller
Here is the detail of the logs of both of the microservices.
Microservice 1 calls Microservice 2
Microserice 1 log:
2017-04-18 17:42:31.887[0;39m [32m INFO [CS Facade,ff711e7b275d03a7,b3f14f1a5cf6bd1d,true][0;39m [35m6280[0;39m [2m---[0;39m [2m[
Microservice 2 log :
[2m2017-04-18 17:43:26.133[0;39m [32m INFO [-,32226de675c3a463,32226de675c3a463,false][0;39m [35m14184[0;39m [2m---[0;39m [2m[nio-8083-exec-1][0;39m [36mc.t.cloud.resource.HelloResource
Although, both have same request call , traceID is different.
It works perfect when both the application are pure spring boot application and no http spring Integration used.
Microservice 1 Code
<int-http:outbound-gateway id="getAccount"
url="http://localhost:8083/rest/hello/micro2"
request-channel="receiveChannel" reply-channel="publishsubscribechannel"
http-method="GET" expected-response-type="java.lang.String">
</int-http:outbound-gateway>
Microservice 2 code
#GetMapping(value = "/micro2")
public String hello() {
LOGGER.info("Reached micro2"+accessor.getCurrentSpan());
return "HelloWorld";
}
I'm sorry but you formatted the code and wrote the text in such a way that I barely understand what the problem is. If both apps are Spring Boot and everything is working fine? That's not strange cause Sleuth is a Boot based library. That means that it's enough to use Boot and Sleuth registers all the necessary components. In case of a non Spring Boot app you basically have to do all the work yourself. That means pass the tracing headers either via HTTP or messaging.
Up to Sleuth 2.1.0, spring-integration won't propagate the X-B3* headers automatically.
https://github.com/spring-cloud/spring-cloud-sleuth/issues/1333 with workaround.
Related
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.
I'm in the process of migrating a Spring Boot 1.5 project to Spring Boot 2.1.8 (JDK 1.8, Kotlin 1.3.50).
I have a few controllers whose methods look like:
#PostMapping("post")
fun post(#RequestBody input: String): Callable<JsonNode> {
return Callable {
requestAsJson(input)
}
}
This works well in Spring Boot 1.5, without any further configuration. However with Spring Boot 2.1.8, the call does not fail but the HTTP response remains empty.
When I use start.spring.io to generate a minimalistic example, it works fine, so I guess that there is something wrong in my configuration.
When I enable debug traces for the Spring MVC, the final trace I get is:
[nio-8080-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Writing [{"data":{"...
[nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Exiting from "ASYNC" dispatch, status 200
So this looks fine to me, but still no response is received (using Curl or Postman to test).
I'm a bit at a loss now, since it was working like a charm in Spring Boot 1.5 and I'm trying to get a hint on how to get out of this issue.
Thanks for any help,
Damien
I had declared a ShallowEtagHeaderFilter bean the following way in my WebMvcConfigurer:
#Bean
fun shallowEtagHeaderFilter(): ShallowEtagHeaderFilter {
return ShallowEtagHeaderFilter()
}
While this was working fine in Spring Boot 1.5, this causes the controller async methods (returning a Callable) to not return any content any longer. Removing this bean for Spring Boot 2.1 restores a normal behavior.
I still need to seek a way to have my e-tag, but for now, this solves the present issue.
I have two Java processes - which get spawned from the same Jar using different run configurations
Process A - Client UI component , Developed Using Spring bean xml based approach. No Spring Boot is there.
Process B - A new Springboot Based component , hosts REST End points.
Now from Process A , on various button click how can I call the REST end points on Process B using Feign Client.
Note - Since Process A is Spring XML based , right at the moment we can not convert that to Spring boot. Hence #EnableFeignClients can not be used to initialise the Feign Clients
So Two questions
1) If the above is possible how to do it ?
2) Till Process A is moved to Spring boot - is Feign still an easier option than spring REST template ?
Feign is a Java to HTTP client binder inspired by Retrofit, JAXRS-2.0, and WebSockets and you can easily use feign without spring boot. And Yes, feign still better option to use because Feign Simplify the HTTP API Clients using declarative way as Spring REST does.
1) Define http methods and endpoints in interface.
#Headers({"Content-Type: application/json"})
public interface NotificationClient {
#RequestLine("POST")
String notify(URI uri, #HeaderMap Map<String, Object> headers, NotificationBody body);
}
2) Create Feign client using Feign.builder() method.
Feign.builder()
.encoder(new JacksonEncoder())
.decoder(customDecoder())
.target(Target.EmptyTarget.create(NotificationClient.class));
There are various decoders available in feign to simplify your tasks.
You are able to just initialise Feign in any code (without spring) just like in the readme example:
public static void main(String... args) {
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
...
}
Please take a look at the getting started guide: feign on github
We have Spring Boot Admin Version-2.0.3 and corresponding Client Version.
Our spring boot instances are deployed to Pivotal Cloud Foundry.
Everything works great, until we deploy a new version of a spring boot instance. A new internal url is generated for the instance, and get registered to admin. But it didn't deregister the removed instance from the admin.
So it leaves spring boot admin in an inconsistent state. such as:
how can I make the registered instance deregister itself when it gets destryed.
I have tried setting:
spring.boot.admin.client.auto-deregistration = true
But it doesn't work as hoped.
The setting auto-deregistration=true causes your client application to send a http delete call to the server on endpoint /instances/{id}. Csrf checking must be disabled for this endpoint as well on the server. This configuration was missing in the sample securityconfiguration in the spring boot admin documentation. ( See https://github.com/codecentric/spring-boot-admin/issues/1251 )
To fix this, replace
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers(adminContextPath + "/instances", adminContextPath + "/actuator/**");
With
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(
new AntPathRequestMatcher(adminContextPath + "/instances", HttpMethod.POST.toString()),
new AntPathRequestMatcher(adminContextPath + "/instances/*", HttpMethod.DELETE.toString()),
new AntPathRequestMatcher(adminContextPath + "/actuator/**")
);
Looking for an example that shows integrating spring cloud sleuth with spring boot amqp (rabbit) publisher and subscriber.
I do see the following messages in the log
2016-10-21 08:35:15.708 INFO [producer,9148f56490e5742f,943ed050691842ab,false] 30928 --- [nio-8080-exec-1] a.b.c.controllers.MessagingController : Received Request to pulish with Activity OrderShipped
2016-10-21 08:35:15.730 INFO [producer,9148f56490e5742f,943ed050691842ab,false] 30928 --- [nio-8080-exec-1] a.b.c.service.ProducerService : Message published
When I look at messages on Queue, I don't see traceId or any other details added to the header. Should I use MessagePostProcessor to add these to the header?
Also what should be done on the receiving service?
We don't instrument Spring AMQP out of the box. You can however use Spring Integration or Spring Cloud Stream that we do support and then everything will work out of the box. If you need to use Spring AMQP for some reason you'll have to instrument the code yourself (and sends us a PR ;) ).
Using Spring AMQP you can set MessagePostProcessor on the RabbitTemplateusing the setBeforePublishPostProcessors method.
We implemented the org.springframework.amqp.core.MessagePostProcessor and Overrided the postProcessMessage method this way:
#Override
public org.springframework.amqp.core.Message postProcessMessage(org.springframework.amqp.core.Message message)
throws AmqpException {
MessagingMessageConverter converter = new MessagingMessageConverter();
MessageBuilder<?> mb = MessageBuilder.fromMessage((Message<?>) converter.fromMessage(message));
inject(tracer.getCurrentSpan(), mb);
return converter.toMessage(mb.build(), message.getMessageProperties());
}
The inject method can now set all the required headers on the message, and it will be passed to the rabbitMq with the changes.
You have a great example of how to implement such inject method in org.springframework.cloud.sleuth.instrument.messaging.MessagingSpanInjector
We are using v1.1.1 of spring-cloud-sleuth-stream so my example is based on this version, in next release(1.2) it will be easier.