Search code examples
istiospring-cloud-sleuth

Java micro service distributed tracing with Istio


Kubernetes and Istio already installed in the cluster. Three micro services deployed as PODs. The flow is

Micro service A to Micro Service B calls => HTTP
Micro service B to Micro service C calls => via Kafka
Micro service A expose a HTTP API to outside 

I guess when client hit the Ingres, Istio generate traceId and spanId in HTTP header and enter to Service A. Are these spanId and traceId propagate to Micro service B and C without using separate API like Spring Cloud sleuth?


Solution

  • No, Istio does not provide tracing headers propagation. However it can be configured on application side without use of 3rd party APIs.

    According to Istio documentation:

    Istio leverages Envoy’s distributed tracing feature to provide tracing integration out of the box. Specifically, Istio provides options to install various tracing backend and configure proxies to send trace spans to them automatically. See Zipkin, Jaeger and LightStep task docs about how Istio works with those tracing systems.


    Istio documentation also has an example of application side header propagation for the bookinfo demo application:

    Trace context propagation

    Although Istio proxies are able to automatically send spans, they need some hints to tie together the entire trace. Applications need to propagate the appropriate HTTP headers so that when the proxies send span information, the spans can be correlated correctly into a single trace.

    To do this, an application needs to collect and propagate the following headers from the incoming request to any outgoing requests:

    • x-request-id
    • x-b3-traceid
    • x-b3-spanid
    • x-b3-parentspanid
    • x-b3-sampled
    • x-b3-flags
    • x-ot-span-context

    Additionally, tracing integrations based on OpenCensus (e.g. Stackdriver) propagate the following headers:

    • x-cloud-trace-context
    • traceparent
    • grpc-trace-bin

    If you look at the sample Python productpage service, for example, you see that the application extracts the required headers from an HTTP request using OpenTracing libraries:

    def getForwardHeaders(request):
        headers = {}
    
        # x-b3-*** headers can be populated using the opentracing span
        span = get_current_span()
        carrier = {}
        tracer.inject(
            span_context=span.context,
            format=Format.HTTP_HEADERS,
            carrier=carrier)
    
        headers.update(carrier)
    
        # ...
    
        incoming_headers = ['x-request-id']
    
        # ...
    
        for ihdr in incoming_headers:
            val = request.headers.get(ihdr)
            if val is not None:
                headers[ihdr] = val
    
        return headers
    
    

    The reviews application (Java) does something similar:

    @GET
    @Path("/reviews/{productId}")
    public Response bookReviewsById(@PathParam("productId") int productId,
                                @HeaderParam("end-user") String user,
                                @HeaderParam("x-request-id") String xreq,
                                @HeaderParam("x-b3-traceid") String xtraceid,
                                @HeaderParam("x-b3-spanid") String xspanid,
                                @HeaderParam("x-b3-parentspanid") String xparentspanid,
                                @HeaderParam("x-b3-sampled") String xsampled,
                                @HeaderParam("x-b3-flags") String xflags,
                                @HeaderParam("x-ot-span-context") String xotspan) {
    
      if (ratings_enabled) {
        JsonObject ratingsResponse = getRatings(Integer.toString(productId), user, xreq, xtraceid, xspanid, xparentspanid, xsampled, xflags, xotspan);
    
    

    When you make downstream calls in your applications, make sure to include these headers.