Sending Zipkin Spans for #FeignClient - spring-boot

I'm running a Spring Boot app using:
Spring Boot 2.3.8
Spring Cloud Hoxton.SR10
I've declared the spring-cloud-starter-zipkin and spring-cloud-starter-openfeign dependencies, and have configured my app to point to a Zipkin server. Its a pretty vanilla setup and configuration (I also declare the spring-cloud-starter-netflix-ribbon and spring-cloud-starter-kubernetes-all dependencies o allow Spring Feign to use k8s service discovery).
My app declares a #SpringFeign annotated interface with a method to call to a remote service S.
So generally zipkin is getting spans from my app (for e.g. incoming REST calls) and B3 headers are being propagated via HTTP to the service S being called through feign.
But zipkin does not report a span from my app representing the Feign call to S.
Is that something that should "just happen", or am I missing a piece of the puzzle?
I can e.g. add #NewSpan to the feign interface method, but that doesn't give me HTTP details for the request/response as span tags. And I rather not do that if this is supposed to work out of the box.

This should be done out of the box: https://docs.spring.io/spring-cloud-sleuth/docs/2.2.7.RELEASE/reference/html/#feign
You can take a look at the feign sample (you need to go back in the history, currently it is for 3.x): https://github.com/spring-cloud/spring-cloud-sleuth/tree/master/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign
In order to see if propagation works, look into the outgoing request, it should contain the tracing-related headers.

Related

Is it possible to disable Spring Cloud Sleuth header propagation based on destination URL?

We're using Brave's ExtraFieldPropagation feature to propagate custom fields (e.g. an internal-only request identifier) between services as HTTP headers.
Some of our services make requests to external services using a RestTemplate or Feign client in the course of processing a request. Since Sleuth enhances all RestTemplate beans and Feign clients with the propagation feature, this means that external services receive the internal-only headers, which I'd like to avoid.
I know of two workarounds that allow me to avoid this behavior, both of which are flawed:
Instantiate a client object manually as opposed to using a #Bean so that Sleuth does not add an interceptor. The downside I see here is that developers have to remember to follow this pattern to avoid leaking information, and this is difficult to enforce.
Add an interceptor that removes these headers from outgoing requests. The downsides here are that a) I need separate interceptors for RestTemplate and Feign clients (not a huge deal); b) it looks like Feign client interceptors do not have a way to influence order of execution (see javadoc here), so I can't guarantee that the new interceptor will run last / after the Sleuth one.
Is there a way to customize Sleuth (e.g. via some kind of injector bean) such that, prior to injecting headers in an outgoing HTTP request, I can reason about the destination of the request? I saw documentation regarding custom injector beans, but it appears those no longer exist in spring boot >= 2. I can't seem to find an equivalent construct in Brave.
You can unsample a given URL which means that the headers will be propagated but not sent to Zipkin. You can't disable instrumentation for only some of the URLs cause we're instrumenting all of the components that are registered as beans.

Stub for Feign client for integration testing

I have a spring cloud project with the following packaging structure
Controller (publishes Rest Endpoint)-->flow (business logic)-->service (calls Feign client with hysterix fallback setup )--> Feign client.
Auto-wiring is done in respective classes e.g. flow is auto-wired in controller and service is auto-wired in flow and so on.
I want to perform integration test, by calling the endpoint published by the controller. The problem is I don't have endpoint accessed by the feign client at the moment (neither original nor spring cloud contract stub is available).
How do I stub the call made by feign client in this case.
You can use Spring Cloud WireMock support and set up an endpoint manually before the tests are called. In the feign configuration you can point manually to an IP and port. The problem is that this test is pretty much useless cause as a consumer you're mocking the producer.
UPDATE
You have a Feign client that will be used to call some external API. What you can do is you can use Spring Cloud WireMock (or just WireMock) to setup a mock of that API. Then you can teach WireMock to behave as you wish and assert whether your client works fine. The problem with such an approach is such that since you, as a client, are setting up the WireMock instance, you can teach it to behave in the way that has nothing to do with the real API. For example you state that if you send a request to endpoint /foo with a method GET then you should get back "BAR" in the response. Then you write a test where your client sends GET # /foo and assert that BAR got properly returned. However that doesn't mean that the other API indeed has that endpoint. So this approach can give you false-positives. You can however use WireMock to assert whether you can properly react to faulty responses like malformed response etc.
In such cases, if you really want to check if you can communicate properly with an API that you don't control, is that you can write tests that will call that real API via a WireMock proxy, you record that traffic and convert it into stubs. You can watch about this more in my presentation here https://www.youtube.com/watch?v=ZyHG-VOzPZg

how to exclude some calls with the Feign from tracing with the cloud sleuth

there's a microservice with spring-boot 1.5 which uses the Feign to communicate with others services, also there's spring-cloud-starter-zipkin which wrapped all calls through the Feign and sends tracing to zipkin server.
The thing is i don't wanna wrap all calls and trace them, there're only several most important to do that.
How can i exclude some calls(methods) with Feign from tracing or exlude some whole Feign client(interface)?
In Sleuth 1.3.x you can create a custom SpanReporter that, before sending a span to Zipkin, would analyze the URL and would not report that span. In Sleuth 2.0.x you can create a custom HttpSampler for the client side (with name sleuthClientSampler)

Dynamically register hystrix commands without javanica annotations in spring boot

We have developed a software proxy based on spring boot and zuul, that is meant to govern services within our integration layer. We do not own the systems consuming the various services, nor do we own the actual services themselves. The services are SOAP based webservices at present. We make use of pre, post , error and route filters. Validations are database driven, including which client is allowed to call what webservice. All service definitions reside in the database (request endpoint, request xsd, response xsd, which clients are allowed to invoke, etc.).
The aim now is to add hystrix commands to handle service failures, as well as a hystrix dashboard.
The standard way to use hystrix commands involves annotating service methods with javanica. Is there a way to dynamically declare/register hystrix commands for these webservices at runtime after reading the configurations from the database? The hystrix interception will need to happen based on the multiple webservice endpoints being invoked from a single point.
Hoping this is achievable ...if not, I would really appreciate any alternative proposals for how hystrix commands could be declared in this way.
Thanks!
You're saying that you are already using Spring Boot and Zuul. How are you mapping the routes? Through the url param? Then you'll have to enroll your own. But if you define the routes as ribbon services and pass the routes as ribbon servers as described in the documentation you will get Hystrix for free.

Rest-SOAP gateaway for external services (Spring + Camel)

I need to build REST-SOAP gateaway between 2 external services
First web services makes SOAP requests and awaits SOAP response. Second service (mine, written in Play Framework 1.2.4) works only using RESTful approach. I don`t want to integrate SOAP related things with second service for many reasons. So I need some third service to act between them.
I have looked into using Spring web-app with Apache Camel, but still can't get the full picture because there are so many modules for Camel. CXF-RS and SOAP components looks promissing, but I can't figure out how to implement proxying using them.
First of all, how to make Camel listen for the specified SOAP request. And then, how to route response from RESTful service back to calling service.
I tried to do it using only spring configuration.
Camel CXF will do the trick for your soap endpoint.
First you need to write an endpoint
#WebService
public interface QuoteInEndpoint {
#WebResult(name = "quote")
public Quote price(#WebParam(name = "symbol") String symbol);
}
Then you need to declare it
<cxf:cxfEndpoint id="quoteIn" address="http://localhost:9002" serviceClass="my.package.QuoteInEndpoint" />
You can then build a route from this endpoint
from("cxf:bean:quoteIn")//
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
//do whatever you need to get your object and transform it for your rest service
}
})//
.to("http://myplayframeworkserver/myservice")//
Camel will start the route, expose the wsdl of your soap service at localhost:9002, and every soap request will be send to your rest server. The process method can be use to shape your objects to the correct format for your rest service (I assume json). Instead of using a processor, you might use another Camel component to do the job (Camel JSON if you need json)
There is no straight forward way to simply proxy between soap and rest. REST services, is all about resources and CRUD - create/read/update/delete. The payload can be whatever, often JSON, but XML, plain text or any orther format is valid. SOAP is XML only with custom definied methods.
I understand the confusion about all the components related to this in Camel.
There are a few aspects you need to have in mind, while chosing your approach.
How much of the SOAP stack do you really need? Most likely you only want the basic featuers, such as receiving a simple soap-envelope and extract the payload without WS-addressing, ws-security etc. etc.
Do you have a contract first or code first approach? That is, do you have your soap service already definied by java classes/interfaces or do you have a WSDL?
Do you have your camel instance deployed inside a servlet container (which is quite common), such as Tomcat, Jetty or a JavaEE app server? If you, you might need to use that servlet container to handle requests by some reason (to get all requests from the same port/server/Domain name by some reason such as web server virtual host, firewalls etc). Then CXF might ge a bit tricky. Otherwise, camel can put up listeners with the built-in jetty core.
So:
Contract first and camel inside serverletcontainer - I prefer spring-ws, since it's very easy to get started with. spring-ws component. Just do the initial wireing in spring and you do not even need to generate things from a WSDL, just simply point out which soap-action, uri or rootq name to get messages from:
from("spring-ws:soapaction:http://example.com/GetFoo?endpointMapping=#endpointMapping")
then you have the XML.
If you need to host the web service from camel, CXF in payload mode is quite decent and will behave pretty much the same.
from("cxf:somename:http://localhost:8765?wsdl=somewsdlfile.wsdl&dataFormat=PAYLOAD")
If you have the service definied in Java already, you could use the SOAP dataformat with the Jetty component to get a very lightweight solution.
SoapJaxbDataFormat soap = new SoapJaxbDataFormat("com.example.customerservice", new ServiceInterfaceStrategy(CustomerService.class));
from("jetty:http://localhost:9832/soapsrv")
.marshal(soap) // and other transforms here
.to("http://somerestservicehost/srv");
Or. go with the full CXF solution with CXF or CXF-bean. There are plenty of examples on the camel website. But the component is rather large and can be somewhat tricky.
For rest, there are also choices, but that part is more straight forward. Rest is very much about creating some content (by extracting it from the soap message, and perhaps map xml to json), which might be easiest to achieve with some plain old java code. Then just invoke a HTTP endpoint towards your rest server. The HTTP4 or HTTP component will do a lot of this for you.
CXFRS is good if you like CXF, and can provide some help, specifically if you want to model your rest service with classes

Resources