From 3551030e3f7cd484f2bb533e7af6f80171434cd0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 8 Feb 2023 11:19:17 +0000 Subject: [PATCH] Add ObservationFilter beans to auto-configured ObservationRegistry Fixes gh-33968 --- .../ObservationAutoConfiguration.java | 8 ++++-- .../ObservationRegistryConfigurer.java | 14 ++++++++-- .../ObservationRegistryPostProcessor.java | 11 ++++++-- .../ObservationAutoConfigurationTests.java | 28 +++++++++++++++++++ 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java index d7c531aa0e..216bc42624 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; import io.micrometer.core.instrument.observation.MeterObservationHandler; import io.micrometer.observation.GlobalObservationConvention; import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationFilter; import io.micrometer.observation.ObservationHandler; import io.micrometer.observation.ObservationPredicate; import io.micrometer.observation.ObservationRegistry; @@ -62,9 +63,10 @@ public class ObservationAutoConfiguration { ObjectProvider observationPredicates, ObjectProvider> observationConventions, ObjectProvider> observationHandlers, - ObjectProvider observationHandlerGrouping) { + ObjectProvider observationHandlerGrouping, + ObjectProvider observationFilters) { return new ObservationRegistryPostProcessor(observationRegistryCustomizers, observationPredicates, - observationConventions, observationHandlers, observationHandlerGrouping); + observationConventions, observationHandlers, observationHandlerGrouping, observationFilters); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurer.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurer.java index e99288ed95..f14ea34618 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurer.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.observation; import java.util.List; import io.micrometer.observation.GlobalObservationConvention; +import io.micrometer.observation.ObservationFilter; import io.micrometer.observation.ObservationHandler; import io.micrometer.observation.ObservationPredicate; import io.micrometer.observation.ObservationRegistry; @@ -48,22 +49,27 @@ class ObservationRegistryConfigurer { private final ObjectProvider observationHandlerGrouping; + private final ObjectProvider observationFilters; + ObservationRegistryConfigurer(ObjectProvider> customizers, ObjectProvider observationPredicates, ObjectProvider> observationConventions, ObjectProvider> observationHandlers, - ObjectProvider observationHandlerGrouping) { + ObjectProvider observationHandlerGrouping, + ObjectProvider observationFilters) { this.customizers = customizers; this.observationPredicates = observationPredicates; this.observationConventions = observationConventions; this.observationHandlers = observationHandlers; this.observationHandlerGrouping = observationHandlerGrouping; + this.observationFilters = observationFilters; } void configure(ObservationRegistry registry) { registerObservationPredicates(registry); registerGlobalObservationConventions(registry); registerHandlers(registry); + registerFilters(registry); customize(registry); } @@ -80,6 +86,10 @@ class ObservationRegistryConfigurer { this.observationConventions.orderedStream().forEach(registry.observationConfig()::observationConvention); } + private void registerFilters(ObservationRegistry registry) { + this.observationFilters.orderedStream().forEach(registry.observationConfig()::observationFilter); + } + @SuppressWarnings("unchecked") private void customize(ObservationRegistry registry) { LambdaSafe.callbacks(ObservationRegistryCustomizer.class, asOrderedList(this.customizers), registry) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryPostProcessor.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryPostProcessor.java index 77d76d4a79..9ad7563a44 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryPostProcessor.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.autoconfigure.observation; import io.micrometer.observation.GlobalObservationConvention; +import io.micrometer.observation.ObservationFilter; import io.micrometer.observation.ObservationHandler; import io.micrometer.observation.ObservationPredicate; import io.micrometer.observation.ObservationRegistry; @@ -44,18 +45,22 @@ class ObservationRegistryPostProcessor implements BeanPostProcessor { private final ObjectProvider observationHandlerGrouping; + private final ObjectProvider observationFilters; + private volatile ObservationRegistryConfigurer configurer; ObservationRegistryPostProcessor(ObjectProvider> observationRegistryCustomizers, ObjectProvider observationPredicates, ObjectProvider> observationConventions, ObjectProvider> observationHandlers, - ObjectProvider observationHandlerGrouping) { + ObjectProvider observationHandlerGrouping, + ObjectProvider observationFilters) { this.observationRegistryCustomizers = observationRegistryCustomizers; this.observationPredicates = observationPredicates; this.observationConventions = observationConventions; this.observationHandlers = observationHandlers; this.observationHandlerGrouping = observationHandlerGrouping; + this.observationFilters = observationFilters; } @Override @@ -70,7 +75,7 @@ class ObservationRegistryPostProcessor implements BeanPostProcessor { if (this.configurer == null) { this.configurer = new ObservationRegistryConfigurer(this.observationRegistryCustomizers, this.observationPredicates, this.observationConventions, this.observationHandlers, - this.observationHandlerGrouping); + this.observationHandlerGrouping, this.observationFilters); } return this.configurer; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java index 7aac4a071a..e9587a6e2c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java @@ -28,6 +28,7 @@ import io.micrometer.core.instrument.search.MeterNotFoundException; import io.micrometer.observation.GlobalObservationConvention; import io.micrometer.observation.Observation; import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.ObservationFilter; import io.micrometer.observation.ObservationHandler; import io.micrometer.observation.ObservationHandler.AllMatchingCompositeObservationHandler; import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler; @@ -176,6 +177,16 @@ class ObservationAutoConfigurationTests { }); } + @Test + void autoConfiguresObservationFilters() { + this.contextRunner.withUserConfiguration(ObservationFilters.class).run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation.start("filtered", observationRegistry).stop(); + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + assertThat(meterRegistry.get("filtered").tag("filter", "one").timer().count()).isOne(); + }); + } + @Test void autoConfiguresGlobalObservationConventions() { this.contextRunner.withUserConfiguration(CustomGlobalObservationConvention.class).run((context) -> { @@ -273,6 +284,23 @@ class ObservationAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class ObservationFilters { + + @Bean + @Order(1) + ObservationFilter observationFilterOne() { + return (context) -> context.addLowCardinalityKeyValue(KeyValue.of("filter", "one")); + } + + @Bean + @Order(0) + ObservationFilter observationFilterTwo() { + return (context) -> context.addLowCardinalityKeyValue(KeyValue.of("filter", "two")); + } + + } + @Configuration(proxyBeanMethods = false) static class CustomGlobalObservationConvention {