Add auto-configuration for Micrometer 2.0.0 Observation API
- Adds a ObservationRegistry bean - Add support for ObservationRegistryCustomizers - Enables timer creation for observations if micrometer-core is on the classpath - Registers ObservationPredicate, GlobalTagsProvider and ObservationHandler on the MeterRegistry - Applies grouping to the ObservationHandlers: MeterObservationHandler are added to a FirstMatchingCompositeObservationHandler - If micrometer-tracing is on the classpath, the TracingObservationHandler are added to a FirstMatchingCompositeObservationHandler Closes gh-29666
This commit is contained in:
parent
4a8901b94c
commit
5ab9112bbc
|
@ -47,7 +47,9 @@ dependencies {
|
|||
optional("com.zaxxer:HikariCP")
|
||||
optional("io.dropwizard.metrics:metrics-jmx")
|
||||
optional("io.lettuce:lettuce-core")
|
||||
optional("io.micrometer:micrometer-observation")
|
||||
optional("io.micrometer:micrometer-core")
|
||||
optional("io.micrometer:micrometer-tracing-api")
|
||||
optional("io.micrometer:micrometer-binders")
|
||||
optional("io.micrometer:micrometer-registry-appoptics")
|
||||
optional("io.micrometer:micrometer-registry-atlas") {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.observation.Observation.GlobalTagsProvider;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationPredicate;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.handler.TracingObservationHandler;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Observation API.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@AutoConfiguration(after = CompositeMeterRegistryAutoConfiguration.class)
|
||||
@ConditionalOnClass(ObservationRegistry.class)
|
||||
public class ObservationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
static ObservationRegistryPostProcessor observationRegistryPostProcessor(
|
||||
ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,
|
||||
ObjectProvider<ObservationPredicate> observationPredicates,
|
||||
ObjectProvider<GlobalTagsProvider<?>> tagProviders,
|
||||
ObjectProvider<ObservationHandler<?>> observationHandlers,
|
||||
ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping) {
|
||||
return new ObservationRegistryPostProcessor(observationRegistryCustomizers, observationPredicates, tagProviders,
|
||||
observationHandlers, observationHandlerGrouping);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ObservationRegistry observationRegistry() {
|
||||
return ObservationRegistry.create();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(MeterRegistry.class)
|
||||
static class MetricsConfiguration {
|
||||
|
||||
@Bean
|
||||
TimerObservationHandlerObservationRegistryCustomizer enableTimerObservationHandler(
|
||||
MeterRegistry meterRegistry) {
|
||||
return new TimerObservationHandlerObservationRegistryCustomizer(meterRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingClass("io.micrometer.tracing.handler.TracingObservationHandler")
|
||||
static class NoTracingConfiguration {
|
||||
|
||||
@Bean
|
||||
ObservationHandlerGrouping noTracingObservationHandlerGrouping() {
|
||||
return new OnlyMetricsObservationHandlerGrouping();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(TracingObservationHandler.class)
|
||||
static class TracingConfiguration {
|
||||
|
||||
@Bean
|
||||
ObservationHandlerGrouping tracingObservationHandlerGrouping() {
|
||||
return new TracingObservationHandlerGrouping();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry.ObservationConfig;
|
||||
|
||||
/**
|
||||
* Strategy to apply {@link ObservationHandler ObservationHandlers} to an
|
||||
* {@link ObservationConfig}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
interface ObservationHandlerGrouping {
|
||||
|
||||
/**
|
||||
* Applies the given list of {@code handlers} to the given {@code config}.
|
||||
* @param handlers the list of observation handlers
|
||||
* @param config the config to apply the handlers to
|
||||
*/
|
||||
void apply(Collection<ObservationHandler<?>> handlers, ObservationConfig config);
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.observation.Observation.GlobalTagsProvider;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationPredicate;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.util.LambdaSafe;
|
||||
|
||||
/**
|
||||
* Configurer to apply {@link ObservationRegistryCustomizer customizers} to
|
||||
* {@link ObservationRegistry observation registries}. Installs
|
||||
* {@link ObservationPredicate observation predicates} and {@link GlobalTagsProvider
|
||||
* global tag providers} into the {@link ObservationRegistry}. Also uses a
|
||||
* {@link ObservationHandlerGrouping} to group handlers, which are then added to the
|
||||
* {@link ObservationRegistry}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class ObservationRegistryConfigurer {
|
||||
|
||||
private final ObjectProvider<ObservationRegistryCustomizer<?>> customizers;
|
||||
|
||||
private final ObjectProvider<ObservationPredicate> observationPredicates;
|
||||
|
||||
private final ObjectProvider<GlobalTagsProvider<?>> tagProviders;
|
||||
|
||||
private final ObjectProvider<ObservationHandler<?>> observationHandlers;
|
||||
|
||||
private final ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping;
|
||||
|
||||
ObservationRegistryConfigurer(ObjectProvider<ObservationRegistryCustomizer<?>> customizers,
|
||||
ObjectProvider<ObservationPredicate> observationPredicates,
|
||||
ObjectProvider<GlobalTagsProvider<?>> tagProviders,
|
||||
ObjectProvider<ObservationHandler<?>> observationHandlers,
|
||||
ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping) {
|
||||
this.customizers = customizers;
|
||||
this.observationPredicates = observationPredicates;
|
||||
this.tagProviders = tagProviders;
|
||||
this.observationHandlers = observationHandlers;
|
||||
this.observationHandlerGrouping = observationHandlerGrouping;
|
||||
}
|
||||
|
||||
void configure(ObservationRegistry registry) {
|
||||
registerObservationPredicates(registry);
|
||||
registerGlobalTagsProvider(registry);
|
||||
registerHandlers(registry);
|
||||
customize(registry);
|
||||
}
|
||||
|
||||
private void registerHandlers(ObservationRegistry registry) {
|
||||
this.observationHandlerGrouping.getObject().apply(asOrderedList(this.observationHandlers),
|
||||
registry.observationConfig());
|
||||
}
|
||||
|
||||
private void registerObservationPredicates(ObservationRegistry registry) {
|
||||
this.observationPredicates.orderedStream().forEach(
|
||||
(observationPredicate) -> registry.observationConfig().observationPredicate(observationPredicate));
|
||||
}
|
||||
|
||||
private void registerGlobalTagsProvider(ObservationRegistry registry) {
|
||||
this.tagProviders.orderedStream()
|
||||
.forEach((tagProvider) -> registry.observationConfig().tagsProvider(tagProvider));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void customize(ObservationRegistry registry) {
|
||||
LambdaSafe.callbacks(ObservationRegistryCustomizer.class, asOrderedList(this.customizers), registry)
|
||||
.withLogger(ObservationRegistryConfigurer.class).invoke((customizer) -> customizer.customize(registry));
|
||||
}
|
||||
|
||||
private <T> List<T> asOrderedList(ObjectProvider<T> provider) {
|
||||
return provider.orderedStream().toList();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
/**
|
||||
* Callback interface that can be used to customize auto-configured
|
||||
* {@link ObservationRegistry observation registries}.
|
||||
*
|
||||
* @param <T> the registry type to customize
|
||||
* @author Moritz Halbritter
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ObservationRegistryCustomizer<T extends ObservationRegistry> {
|
||||
|
||||
/**
|
||||
* Customize the given {@code registry}.
|
||||
* @param registry the registry to customize
|
||||
*/
|
||||
void customize(T registry);
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.observation.Observation.GlobalTagsProvider;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationPredicate;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} that delegates to a lazily created
|
||||
* {@link ObservationRegistryConfigurer} to post-process {@link ObservationRegistry}
|
||||
* beans.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class ObservationRegistryPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers;
|
||||
|
||||
private final ObjectProvider<ObservationPredicate> observationPredicates;
|
||||
|
||||
private final ObjectProvider<GlobalTagsProvider<?>> tagProviders;
|
||||
|
||||
private final ObjectProvider<ObservationHandler<?>> observationHandlers;
|
||||
|
||||
private final ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping;
|
||||
|
||||
private volatile ObservationRegistryConfigurer configurer;
|
||||
|
||||
ObservationRegistryPostProcessor(ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,
|
||||
ObjectProvider<ObservationPredicate> observationPredicates,
|
||||
ObjectProvider<GlobalTagsProvider<?>> tagProviders,
|
||||
ObjectProvider<ObservationHandler<?>> observationHandlers,
|
||||
ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping) {
|
||||
this.observationRegistryCustomizers = observationRegistryCustomizers;
|
||||
this.observationPredicates = observationPredicates;
|
||||
this.tagProviders = tagProviders;
|
||||
this.observationHandlers = observationHandlers;
|
||||
this.observationHandlerGrouping = observationHandlerGrouping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof ObservationRegistry) {
|
||||
getConfigurer().configure((ObservationRegistry) bean);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private ObservationRegistryConfigurer getConfigurer() {
|
||||
if (this.configurer == null) {
|
||||
this.configurer = new ObservationRegistryConfigurer(this.observationRegistryCustomizers,
|
||||
this.observationPredicates, this.tagProviders, this.observationHandlers,
|
||||
this.observationHandlerGrouping);
|
||||
}
|
||||
return this.configurer;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.core.instrument.observation.MeterObservationHandler;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry.ObservationConfig;
|
||||
|
||||
/**
|
||||
* {@link ObservationHandlerGrouping} used by {@link ObservationAutoConfiguration} if
|
||||
* micrometer-tracing is not on the classpath.
|
||||
*
|
||||
* Groups all {@link MeterObservationHandler} into a
|
||||
* {@link FirstMatchingCompositeObservationHandler}. All other handlers are added to the
|
||||
* {@link ObservationConfig} directly.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class OnlyMetricsObservationHandlerGrouping implements ObservationHandlerGrouping {
|
||||
|
||||
@Override
|
||||
public void apply(Collection<ObservationHandler<?>> handlers, ObservationConfig config) {
|
||||
List<ObservationHandler<?>> meterObservationHandlers = new ArrayList<>();
|
||||
for (ObservationHandler<?> handler : handlers) {
|
||||
if (handler instanceof MeterObservationHandler<?>) {
|
||||
meterObservationHandlers.add(handler);
|
||||
}
|
||||
else {
|
||||
config.observationHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
if (!meterObservationHandlers.isEmpty()) {
|
||||
config.observationHandler(
|
||||
new FirstMatchingCompositeObservationHandler(castToRawType(meterObservationHandlers)));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private List<ObservationHandler> castToRawType(List<ObservationHandler<?>> handlers) {
|
||||
// See https://github.com/micrometer-metrics/micrometer/issues/3064
|
||||
return (List) handlers;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.observation.TimerObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
/**
|
||||
* Registers the {@link TimerObservationHandler} with a {@link ObservationRegistry}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class TimerObservationHandlerObservationRegistryCustomizer
|
||||
implements ObservationRegistryCustomizer<ObservationRegistry> {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
TimerObservationHandlerObservationRegistryCustomizer(MeterRegistry meterRegistry) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(ObservationRegistry registry) {
|
||||
registry.observationConfig().observationHandler(new TimerObservationHandler(this.meterRegistry));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.core.instrument.observation.MeterObservationHandler;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry.ObservationConfig;
|
||||
import io.micrometer.tracing.handler.TracingObservationHandler;
|
||||
|
||||
/**
|
||||
* {@link ObservationHandlerGrouping} used by {@link ObservationAutoConfiguration} if
|
||||
* micrometer-tracing is on the classpath.
|
||||
*
|
||||
* Groups all {@link MeterObservationHandler} into a
|
||||
* {@link FirstMatchingCompositeObservationHandler}, and all
|
||||
* {@link TracingObservationHandler} into a
|
||||
* {@link FirstMatchingCompositeObservationHandler}. All other handlers are added to the
|
||||
* {@link ObservationConfig} directly.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class TracingObservationHandlerGrouping implements ObservationHandlerGrouping {
|
||||
|
||||
@Override
|
||||
public void apply(Collection<ObservationHandler<?>> handlers, ObservationConfig config) {
|
||||
List<ObservationHandler<?>> meterObservationHandlers = new ArrayList<>();
|
||||
List<ObservationHandler<?>> tracingObservationHandlers = new ArrayList<>();
|
||||
for (ObservationHandler<?> handler : handlers) {
|
||||
if (handler instanceof MeterObservationHandler<?>) {
|
||||
meterObservationHandlers.add(handler);
|
||||
}
|
||||
else if (handler instanceof TracingObservationHandler<?>) {
|
||||
tracingObservationHandlers.add(handler);
|
||||
}
|
||||
else {
|
||||
config.observationHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
if (!meterObservationHandlers.isEmpty()) {
|
||||
config.observationHandler(
|
||||
new FirstMatchingCompositeObservationHandler(castToRawType(meterObservationHandlers)));
|
||||
}
|
||||
if (!tracingObservationHandlers.isEmpty()) {
|
||||
config.observationHandler(
|
||||
new FirstMatchingCompositeObservationHandler(castToRawType(tracingObservationHandlers)));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private List<ObservationHandler> castToRawType(List<ObservationHandler<?>> handlers) {
|
||||
// See https://github.com/micrometer-metrics/micrometer/issues/3064
|
||||
return (List) handlers;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for the Micrometer Observation API.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
|
@ -81,6 +81,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat.TomcatMetricsA
|
|||
org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.mongo.MongoReactiveHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.quartz.QuartzEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.r2dbc.ConnectionFactoryHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.redis.RedisHealthContributorAutoConfiguration
|
||||
|
@ -97,4 +98,4 @@ org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceEndpointAutoC
|
|||
org.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
|
||||
|
|
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.common.Tag;
|
||||
import io.micrometer.common.Tags;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.observation.MeterObservationHandler;
|
||||
import io.micrometer.core.instrument.search.MeterNotFoundException;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.Observation.Context;
|
||||
import io.micrometer.observation.Observation.GlobalTagsProvider;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationHandler.AllMatchingCompositeObservationHandler;
|
||||
import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;
|
||||
import io.micrometer.observation.ObservationPredicate;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import io.micrometer.tracing.handler.TracingObservationHandler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Tests for {@link ObservationAutoConfiguration}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class ObservationAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple())
|
||||
.withClassLoader(new FilteredClassLoader("io.micrometer.tracing"))
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class));
|
||||
|
||||
private final ApplicationContextRunner tracingContextRunner = new ApplicationContextRunner()
|
||||
.with(MetricsRun.simple()).withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void autoConfiguresTimerObservationHandler() {
|
||||
this.contextRunner.run((context) -> {
|
||||
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
|
||||
Observation.start("test-observation", observationRegistry).stop();
|
||||
// When a TimerObservationHandler is registered, every stopped Observation
|
||||
// leads to a timer
|
||||
MeterRegistry meterRegistry = context.getBean(MeterRegistry.class);
|
||||
assertThat(meterRegistry.get("test-observation").timer().count()).isEqualTo(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsTimerObservationHandlerToBeDisabled() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(MeterRegistry.class))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(TimerObservationHandlerObservationRegistryCustomizer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresObservationPredicates() {
|
||||
this.contextRunner.withUserConfiguration(ObservationPredicates.class).run((context) -> {
|
||||
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
|
||||
// This is allowed by ObservationPredicates.customPredicate
|
||||
Observation.start("observation1", observationRegistry).start().stop();
|
||||
// This isn't allowed by ObservationPredicates.customPredicate
|
||||
Observation.start("observation2", observationRegistry).start().stop();
|
||||
MeterRegistry meterRegistry = context.getBean(MeterRegistry.class);
|
||||
assertThat(meterRegistry.get("observation1").timer().count()).isEqualTo(1);
|
||||
assertThatThrownBy(() -> meterRegistry.get("observation2").timer())
|
||||
.isInstanceOf(MeterNotFoundException.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresGlobalTagsProvider() {
|
||||
this.contextRunner.withUserConfiguration(GlobalTagsProviders.class).run((context) -> {
|
||||
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
|
||||
Context micrometerContext = new Context();
|
||||
Observation.start("test-observation", micrometerContext, observationRegistry).stop();
|
||||
assertThat(micrometerContext.getAllTags()).containsExactly(Tag.of("tag1", "value1"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresObservationHandler() {
|
||||
this.contextRunner.withUserConfiguration(ObservationHandlers.class).run((context) -> {
|
||||
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
|
||||
List<ObservationHandler<?>> handlers = context.getBean(CalledHandlers.class).getCalledHandlers();
|
||||
Observation.start("test-observation", observationRegistry);
|
||||
assertThat(handlers).hasSize(2);
|
||||
// Regular handlers are registered first
|
||||
assertThat(handlers.get(0)).isInstanceOf(CustomObservationHandler.class);
|
||||
// Multiple MeterObservationHandler are wrapped in
|
||||
// FirstMatchingCompositeObservationHandler, which calls only the first
|
||||
// one
|
||||
assertThat(handlers.get(1)).isInstanceOf(CustomMeterObservationHandler.class);
|
||||
assertThat(((CustomMeterObservationHandler) handlers.get(1)).getName())
|
||||
.isEqualTo("customMeterObservationHandler1");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresObservationHandlerWhenTracingIsActive() {
|
||||
this.tracingContextRunner.withUserConfiguration(ObservationHandlersTracing.class).run((context) -> {
|
||||
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
|
||||
List<ObservationHandler<?>> handlers = context.getBean(CalledHandlers.class).getCalledHandlers();
|
||||
Observation.start("test-observation", observationRegistry);
|
||||
assertThat(handlers).hasSize(3);
|
||||
// Regular handlers are registered first
|
||||
assertThat(handlers.get(0)).isInstanceOf(CustomObservationHandler.class);
|
||||
// Multiple MeterObservationHandler are wrapped in
|
||||
// FirstMatchingCompositeObservationHandler, which calls only the first
|
||||
// one
|
||||
assertThat(handlers.get(1)).isInstanceOf(CustomMeterObservationHandler.class);
|
||||
assertThat(((CustomMeterObservationHandler) handlers.get(1)).getName())
|
||||
.isEqualTo("customMeterObservationHandler1");
|
||||
// Multiple TracingObservationHandler are wrapped in
|
||||
// FirstMatchingCompositeObservationHandler, which calls only the first
|
||||
// one
|
||||
assertThat(handlers.get(2)).isInstanceOf(CustomTracingObservationHandler.class);
|
||||
assertThat(((CustomTracingObservationHandler) handlers.get(2)).getName())
|
||||
.isEqualTo("customTracingHandler1");
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ObservationPredicates {
|
||||
|
||||
@Bean
|
||||
ObservationPredicate customPredicate() {
|
||||
return (s, context) -> s.equals("observation1");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class GlobalTagsProviders {
|
||||
|
||||
@Bean
|
||||
GlobalTagsProvider<?> customTagsProvider() {
|
||||
return new GlobalTagsProvider<>() {
|
||||
@Override
|
||||
public boolean supportsContext(Context context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tags getLowCardinalityTags(Context context) {
|
||||
return Tags.of("tag1", "value1");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(CalledHandlersConfiguration.class)
|
||||
static class ObservationHandlers {
|
||||
|
||||
@Bean
|
||||
@Order(4)
|
||||
AllMatchingCompositeObservationHandler customAllMatchingCompositeObservationHandler() {
|
||||
return new AllMatchingCompositeObservationHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(3)
|
||||
FirstMatchingCompositeObservationHandler customFirstMatchingCompositeObservationHandler() {
|
||||
return new FirstMatchingCompositeObservationHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(2)
|
||||
ObservationHandler<Context> customObservationHandler(CalledHandlers calledHandlers) {
|
||||
return new CustomObservationHandler(calledHandlers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
MeterObservationHandler<Context> customMeterObservationHandler2(CalledHandlers calledHandlers) {
|
||||
return new CustomMeterObservationHandler("customMeterObservationHandler2", calledHandlers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
MeterObservationHandler<Context> customMeterObservationHandler1(CalledHandlers calledHandlers) {
|
||||
return new CustomMeterObservationHandler("customMeterObservationHandler1", calledHandlers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(CalledHandlersConfiguration.class)
|
||||
static class ObservationHandlersTracing {
|
||||
|
||||
@Bean
|
||||
@Order(6)
|
||||
CustomTracingObservationHandler customTracingHandler2(CalledHandlers calledHandlers) {
|
||||
return new CustomTracingObservationHandler("customTracingHandler2", calledHandlers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(5)
|
||||
CustomTracingObservationHandler customTracingHandler1(CalledHandlers calledHandlers) {
|
||||
return new CustomTracingObservationHandler("customTracingHandler1", calledHandlers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(4)
|
||||
AllMatchingCompositeObservationHandler customAllMatchingCompositeObservationHandler() {
|
||||
return new AllMatchingCompositeObservationHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(3)
|
||||
FirstMatchingCompositeObservationHandler customFirstMatchingCompositeObservationHandler() {
|
||||
return new FirstMatchingCompositeObservationHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(2)
|
||||
ObservationHandler<Context> customObservationHandler(CalledHandlers calledHandlers) {
|
||||
return new CustomObservationHandler(calledHandlers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
MeterObservationHandler<Context> customMeterObservationHandler2(CalledHandlers calledHandlers) {
|
||||
return new CustomMeterObservationHandler("customMeterObservationHandler2", calledHandlers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
MeterObservationHandler<Context> customMeterObservationHandler1(CalledHandlers calledHandlers) {
|
||||
return new CustomMeterObservationHandler("customMeterObservationHandler1", calledHandlers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CustomTracingObservationHandler implements TracingObservationHandler<Context> {
|
||||
|
||||
private final Tracer tracer = Mockito.mock(Tracer.class, Answers.RETURNS_MOCKS);
|
||||
|
||||
private final String name;
|
||||
|
||||
private final CalledHandlers calledHandlers;
|
||||
|
||||
CustomTracingObservationHandler(String name, CalledHandlers calledHandlers) {
|
||||
this.name = name;
|
||||
this.calledHandlers = calledHandlers;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer getTracer() {
|
||||
return this.tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Context context) {
|
||||
this.calledHandlers.onCalled(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsContext(Context context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CalledHandlers {
|
||||
|
||||
private final List<ObservationHandler<?>> calledHandlers = new ArrayList<>();
|
||||
|
||||
void onCalled(ObservationHandler<?> handler) {
|
||||
this.calledHandlers.add(handler);
|
||||
}
|
||||
|
||||
List<ObservationHandler<?>> getCalledHandlers() {
|
||||
return this.calledHandlers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CalledHandlersConfiguration {
|
||||
|
||||
@Bean
|
||||
CalledHandlers calledHandlers() {
|
||||
return new CalledHandlers();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CustomObservationHandler implements ObservationHandler<Context> {
|
||||
|
||||
private final CalledHandlers calledHandlers;
|
||||
|
||||
CustomObservationHandler(CalledHandlers calledHandlers) {
|
||||
this.calledHandlers = calledHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Context context) {
|
||||
this.calledHandlers.onCalled(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsContext(Context context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CustomMeterObservationHandler implements MeterObservationHandler<Context> {
|
||||
|
||||
private final CalledHandlers calledHandlers;
|
||||
|
||||
private final String name;
|
||||
|
||||
CustomMeterObservationHandler(String name, CalledHandlers calledHandlers) {
|
||||
this.name = name;
|
||||
this.calledHandlers = calledHandlers;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Context context) {
|
||||
this.calledHandlers.onCalled(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsContext(Context context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link ObservationRegistryConfigurer} and
|
||||
* {@link ObservationRegistryPostProcessor}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class ObservationRegistryConfigurerIntegrationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void customizersAreCalledInOrder() {
|
||||
this.contextRunner.withUserConfiguration(Customizers.class).run((context) -> {
|
||||
CalledCustomizers calledCustomizers = context.getBean(CalledCustomizers.class);
|
||||
Customizer1 customizer1 = context.getBean(Customizer1.class);
|
||||
Customizer2 customizer2 = context.getBean(Customizer2.class);
|
||||
|
||||
assertThat(calledCustomizers.getCustomizers()).containsExactly(customizer1, customizer2);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class Customizers {
|
||||
|
||||
@Bean
|
||||
CalledCustomizers calledCustomizers() {
|
||||
return new CalledCustomizers();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
Customizer1 customizer1(CalledCustomizers calledCustomizers) {
|
||||
return new Customizer1(calledCustomizers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(2)
|
||||
Customizer2 customizer2(CalledCustomizers calledCustomizers) {
|
||||
return new Customizer2(calledCustomizers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CalledCustomizers {
|
||||
|
||||
private final List<ObservationRegistryCustomizer<?>> customizers = new ArrayList<>();
|
||||
|
||||
void onCalled(ObservationRegistryCustomizer<?> customizer) {
|
||||
this.customizers.add(customizer);
|
||||
}
|
||||
|
||||
List<ObservationRegistryCustomizer<?>> getCustomizers() {
|
||||
return this.customizers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Customizer1 implements ObservationRegistryCustomizer<ObservationRegistry> {
|
||||
|
||||
private final CalledCustomizers calledCustomizers;
|
||||
|
||||
Customizer1(CalledCustomizers calledCustomizers) {
|
||||
this.calledCustomizers = calledCustomizers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(ObservationRegistry registry) {
|
||||
this.calledCustomizers.onCalled(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Customizer2 implements ObservationRegistryCustomizer<ObservationRegistry> {
|
||||
|
||||
private final CalledCustomizers calledCustomizers;
|
||||
|
||||
Customizer2(CalledCustomizers calledCustomizers) {
|
||||
this.calledCustomizers = calledCustomizers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(ObservationRegistry registry) {
|
||||
this.calledCustomizers.onCalled(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link TimerObservationHandlerObservationRegistryCustomizer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class TimerObservationHandlerObservationRegistryCustomizerTests {
|
||||
|
||||
@Test
|
||||
void customizeInstallsTimerObservationHandler() {
|
||||
MeterRegistry meterRegistry = new SimpleMeterRegistry();
|
||||
TimerObservationHandlerObservationRegistryCustomizer sut = new TimerObservationHandlerObservationRegistryCustomizer(
|
||||
meterRegistry);
|
||||
ObservationRegistry observationRegistry = ObservationRegistry.create();
|
||||
sut.customize(observationRegistry);
|
||||
Observation.start("test-1", observationRegistry).stop();
|
||||
assertThat(meterRegistry.find("test-1").timer().count()).isEqualTo(1);
|
||||
}
|
||||
|
||||
}
|
|
@ -22,8 +22,10 @@ dependencies {
|
|||
optional("com.sun.mail:jakarta.mail")
|
||||
optional("com.zaxxer:HikariCP")
|
||||
optional("io.lettuce:lettuce-core")
|
||||
optional("io.micrometer:micrometer-observation")
|
||||
optional("io.micrometer:micrometer-core")
|
||||
optional("io.micrometer:micrometer-binders")
|
||||
optional("io.micrometer:micrometer-tracing-api")
|
||||
optional("io.micrometer:micrometer-registry-prometheus")
|
||||
optional("io.prometheus:simpleclient_pushgateway") {
|
||||
exclude(group: "javax.xml.bind", module: "jaxb-api")
|
||||
|
|
|
@ -976,7 +976,7 @@ bom {
|
|||
]
|
||||
}
|
||||
}
|
||||
library("Micrometer", "2.0.0-M3") {
|
||||
library("Micrometer", "2.0.0-SNAPSHOT") {
|
||||
group("io.micrometer") {
|
||||
modules = [
|
||||
"micrometer-registry-stackdriver" {
|
||||
|
@ -988,6 +988,13 @@ bom {
|
|||
]
|
||||
}
|
||||
}
|
||||
library("Micrometer Tracing", "1.0.0-SNAPSHOT") {
|
||||
group("io.micrometer") {
|
||||
modules = [
|
||||
"micrometer-tracing-api"
|
||||
]
|
||||
}
|
||||
}
|
||||
library("MIMEPull", "1.9.15") {
|
||||
group("org.jvnet.mimepull") {
|
||||
modules = [
|
||||
|
|
|
@ -7,6 +7,7 @@ description = "Starter for using Spring Boot's Actuator which provides productio
|
|||
dependencies {
|
||||
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter"))
|
||||
api(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
|
||||
api("io.micrometer:micrometer-observation")
|
||||
api("io.micrometer:micrometer-core")
|
||||
api("io.micrometer:micrometer-binders")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue