Search code examples
rabbitmqapache-cameljaegeropentracing

How to change the operation name of a span with Apache Camel OpenTracing component?


I successfully added Apache Camel's OpenTracing component to my application. I can see traces in Jaeger UI. But the traces for the RabbitMQ component show only the exchange name without the routing key as operation name. Because of my application uses only one exchange with different routing keys, I need to see the routing key as operation name in my traces.

Research

With OpenTracing Spring RabbitMQ I could expose another customized RabbitMqSpanDecorator, see Span decorator:

Note: you can customize your spans by declaring an overridden RabbitMqSpanDecorator bean.

(However, I coulnd't change the operation name with the RabbitMqSpanDecorator at all, because the operation name is hard coded to producer or consumer.)

Unfortunately Apache Camel uses its own different implementation of a RabbitmqSpanDecorator to decorate spans. I wrote a custom class by overiding Apache Camel's RabbitmqSpanDecorator, but my custom class wasn't used.

Question

How can I change the operation name of a span with Apache Camel OpenTracing component for Apache Camel RabbitMQ component?


Solution

  • It is possible to change the Tracer implementation with ServiceLoader, see OpenTracing:

    EXPLICIT

    Include the camel-opentracing component in your POM, along with any specific dependencies associated with the chosen OpenTracing compliant Tracer.

    To explicitly configure OpenTracing support, instantiate the OpenTracingTracer and initialize the camel context. You can optionally specify a Tracer, or alternatively it can be implicitly discovered using the Registry or ServiceLoader.

    With the DefaultTracer it is also possible to change the RabbitmqSpanDecorator with ServiceLoader, see Tracer.java:

    static {
        ServiceLoader.load(SpanDecorator.class).forEach(d -> {
            SpanDecorator existing = DECORATORS.get(d.getComponent());
            // Add span decorator if no existing decorator for the component,
            // or if derived from the existing decorator's class, allowing
            // custom decorators to be added if they extend the standard
            // decorators
            if (existing == null || existing.getClass().isInstance(d)) {
                DECORATORS.put(d.getComponent(), d);
            }
        });
    }
    

    Therefore, I had to add a file org.apache.camel.tracing.SpanDecorator containing the name of my custom RabbitmqSpanDecorator, see ServiceLoader:

    Deploying service providers on the class path

    A service provider that is packaged as a JAR file for the class path is identified by placing a provider-configuration file in the resource directory META-INF/services. The name of the provider-configuration file is the fully qualified binary name of the service. The provider-configuration file contains a list of fully qualified binary names of service providers, one per line.

    My custom RabbitmqSpanDecorator:

    public class CustomRabbitmqSpanDecorator extends RabbitmqSpanDecorator {
    
      @Override
      public String getOperationName(Exchange exchange, Endpoint endpoint) {
    
        return ((RabbitMQEndpoint) endpoint).getRoutingKey();
      }
    }