spring-bootrabbitmqmetricsspring-rabbitrabbitmq-exchange

How to get metrics for RabbitMQ exchanges with Spring Boot?


Spring Boot automagically (with the actuator) provides metrics for queues (spring_rabbitmq_listener*).

Is there a way to get similar metrics for the exchanges a services sends to?

The application is using

all in 3.1.0

I've tried rabbitTemplate.setObservationEnabled(true); but that doesn't help.


Solution

  • Unlike the listener containers, the RabbitTemplate (used to send messages to exchanges) does not support classic Micrometer Timers.

    However, starting with version 3.0, you can enable Observation by Micrometer which does include Micrometer metrics (as well as adding tracing capabilities).

    Note that if you enable observation for the listener containers, the default metrics are disabled (because it doesn't make sense to maintain both). The observation metrics have slightly different tags.

    https://docs.spring.io/spring-amqp/docs/current/reference/html/#micrometer-observation

    Using Micrometer for observation is now supported, since version 3.0, for the RabbitTemplate and listener containers.

    Set observationEnabled on each component to enable observation; this will disable Micrometer Timers because the timers will now be managed with each observation. When using annotated listeners, set observationEnabled on the container factory.

    EDIT

    This works fine for me:

    @SpringBootApplication
    public class So76530102Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So76530102Application.class, args).close();
        }
    
        @Bean
        ApplicationRunner runner(RabbitTemplate template, MeterRegistry registry) {
            template.setObservationEnabled(true);
            return args -> {
                template.convertAndSend("foo", "bar", "test");
                Timer timer = registry.get("spring.rabbit.template")
                    .tagKeys("spring.rabbit.template.name", "error")
                    .timer();
                System.out.println(timer.count());
            };
        }
    
    }
    
    1
    

    However, the timer does not contain any information about the exchange or routing key (the trace data does have that information with the form exchange/rk).

    EDIT2

    If you want to add the exhange/rk as a tag to the meter...

    @SpringBootApplication
    public class So76530102Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So76530102Application.class, args).close();
        }
    
        @Bean
        ApplicationRunner runner(RabbitTemplate template, MeterRegistry registry) {
            template.setObservationEnabled(true);
            template.setObservationConvention(new MyConvention());
            return args -> {
                template.convertAndSend("foo", "bar", "test");
                registry.getMeters().stream()
                    .filter(m -> m.getId().getName().equals("spring.rabbit.template"))
                    .forEach(m -> System.out.println(m.getId()));
                Timer timer = registry.get("spring.rabbit.template")
                    .tagKeys("spring.rabbit.template.name", "error")
                    .tag("dest", "foo/bar")
                    .timer();
                System.out.println(timer.count());
            };
        }
    
    }
    
    class MyConvention extends DefaultRabbitTemplateObservationConvention {
    
        @Override
        public KeyValues getLowCardinalityKeyValues(RabbitMessageSenderContext context) {
            return super.getLowCardinalityKeyValues(context).and("dest", context.getDestination());
        }
    
    }
    
    MeterId{name='spring.rabbit.template', tags=[tag(dest=foo/bar),tag(error=none),tag(spring.rabbit.template.name=rabbitTemplate)]}
    1