Add property for common key/values on observations
- Deprecates 'management.metrics.tags.*' Closes gh-33241
This commit is contained in:
parent
214f06083b
commit
5b06224af5
|
|
@ -79,6 +79,7 @@ public class MetricsProperties {
|
|||
return this.enable;
|
||||
}
|
||||
|
||||
@DeprecatedConfigurationProperty(replacement = "management.observations.key-values")
|
||||
public Map<String, String> getTags() {
|
||||
return this.tags;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClas
|
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Observation API.
|
||||
|
|
@ -75,6 +76,12 @@ public class ObservationAutoConfiguration {
|
|||
return ObservationRegistry.create();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
PropertiesObservationFilter propertiesObservationFilter(ObservationProperties properties) {
|
||||
return new PropertiesObservationFilter(properties);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(MeterRegistry.class)
|
||||
@ConditionalOnMissingClass("io.micrometer.tracing.Tracer")
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
|
|
@ -30,10 +33,23 @@ public class ObservationProperties {
|
|||
|
||||
private final Http http = new Http();
|
||||
|
||||
/**
|
||||
* Common key-values that are applied to every observation.
|
||||
*/
|
||||
private Map<String, String> keyValues = new LinkedHashMap<>();
|
||||
|
||||
public Http getHttp() {
|
||||
return this.http;
|
||||
}
|
||||
|
||||
public Map<String, String> getKeyValues() {
|
||||
return this.keyValues;
|
||||
}
|
||||
|
||||
public void setKeyValues(Map<String, String> keyValues) {
|
||||
this.keyValues = keyValues;
|
||||
}
|
||||
|
||||
public static class Http {
|
||||
|
||||
private final Client client = new Client();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.
|
||||
* 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.Map.Entry;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
import io.micrometer.observation.Observation.Context;
|
||||
import io.micrometer.observation.ObservationFilter;
|
||||
|
||||
/**
|
||||
* {@link ObservationFilter} to apply settings from {@link ObservationProperties}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class PropertiesObservationFilter implements ObservationFilter {
|
||||
|
||||
private final ObservationFilter delegate;
|
||||
|
||||
PropertiesObservationFilter(ObservationProperties properties) {
|
||||
this.delegate = createDelegate(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context map(Context context) {
|
||||
return this.delegate.map(context);
|
||||
}
|
||||
|
||||
private static ObservationFilter createDelegate(ObservationProperties properties) {
|
||||
if (properties.getKeyValues().isEmpty()) {
|
||||
return (context) -> context;
|
||||
}
|
||||
KeyValues keyValues = KeyValues.of(properties.getKeyValues().entrySet(), Entry::getKey, Entry::getValue);
|
||||
return (context) -> context.addLowCardinalityKeyValues(keyValues);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -189,6 +189,21 @@ class ObservationAutoConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupplyPropertiesObservationFilterBean() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesObservationFilter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldApplyCommonKeyValuesToObservations() {
|
||||
this.contextRunner.withPropertyValues("management.observations.key-values.a=alpha").run((context) -> {
|
||||
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
|
||||
Observation.start("keyvalues", observationRegistry).stop();
|
||||
MeterRegistry meterRegistry = context.getBean(MeterRegistry.class);
|
||||
assertThat(meterRegistry.get("keyvalues").tag("a", "alpha").timer().count()).isOne();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresGlobalObservationConventions() {
|
||||
this.contextRunner.withUserConfiguration(CustomGlobalObservationConvention.class).run((context) -> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.
|
||||
* 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.common.KeyValue;
|
||||
import io.micrometer.common.KeyValues;
|
||||
import io.micrometer.observation.Observation.Context;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertiesObservationFilter}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class PropertiesObservationFilterTests {
|
||||
|
||||
@Test
|
||||
void shouldDoNothingIfKeyValuesAreEmpty() {
|
||||
PropertiesObservationFilter filter = createFilter();
|
||||
Context mapped = mapContext(filter, "a", "alpha");
|
||||
assertThat(mapped.getLowCardinalityKeyValues()).containsExactly(KeyValue.of("a", "alpha"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddKeyValues() {
|
||||
PropertiesObservationFilter filter = createFilter("b", "beta");
|
||||
Context mapped = mapContext(filter, "a", "alpha");
|
||||
assertThat(mapped.getLowCardinalityKeyValues()).containsExactly(KeyValue.of("a", "alpha"),
|
||||
KeyValue.of("b", "beta"));
|
||||
}
|
||||
|
||||
private static Context mapContext(PropertiesObservationFilter filter, String... initialKeyValues) {
|
||||
Context context = new Context();
|
||||
context.addLowCardinalityKeyValues(KeyValues.of(initialKeyValues));
|
||||
return filter.map(context);
|
||||
}
|
||||
|
||||
private static PropertiesObservationFilter createFilter(String... keyValues) {
|
||||
ObservationProperties properties = new ObservationProperties();
|
||||
for (int i = 0; i < keyValues.length; i += 2) {
|
||||
properties.getKeyValues().put(keyValues[i], keyValues[i + 1]);
|
||||
}
|
||||
return new PropertiesObservationFilter(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1100,19 +1100,8 @@ These use the global registry that is not Spring-managed.
|
|||
|
||||
[[actuator.metrics.customizing.common-tags]]
|
||||
==== Common Tags
|
||||
Common tags are generally used for dimensional drill-down on the operating environment, such as host, instance, region, stack, and others.
|
||||
Commons tags are applied to all meters and can be configured, as the following example shows:
|
||||
|
||||
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
|
||||
----
|
||||
management:
|
||||
metrics:
|
||||
tags:
|
||||
region: "us-east-1"
|
||||
stack: "prod"
|
||||
----
|
||||
|
||||
The preceding example adds `region` and `stack` tags to all meters with a value of `us-east-1` and `prod`, respectively.
|
||||
You can configure common tags using the <<actuator#actuator.observability.common-key-values, configprop:management.observations.key-values[] property>>.
|
||||
|
||||
NOTE: The order of common tags is important if you use Graphite.
|
||||
As the order of common tags cannot be guaranteed by using this approach, Graphite users are advised to define a custom `MeterFilter` instead.
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ To create your own observations (which will lead to metrics and traces), you can
|
|||
|
||||
include::code:MyCustomObservation[]
|
||||
|
||||
NOTE: Low cardinality tags will be added to metrics and traces, while high cardinality tags will only be added to traces.
|
||||
NOTE: Low cardinality key-values will be added to metrics and traces, while high cardinality key-values will only be added to traces.
|
||||
|
||||
Beans of type `ObservationPredicate`, `GlobalObservationConvention` and `ObservationHandler` will be automatically registered on the `ObservationRegistry`.
|
||||
Beans of type `ObservationPredicate`, `GlobalObservationConvention`, `ObservationFilter` and `ObservationHandler` will be automatically registered on the `ObservationRegistry`.
|
||||
You can additionally register any number of `ObservationRegistryCustomizer` beans to further configure the registry.
|
||||
|
||||
For more details please see the https://micrometer.io/docs/observation[Micrometer Observation documentation].
|
||||
|
|
@ -21,4 +21,20 @@ For JDBC, the https://github.com/jdbc-observations/datasource-micrometer[Datasou
|
|||
Read more about it https://jdbc-observations.github.io/datasource-micrometer/docs/current/docs/html/[in the reference documentation].
|
||||
For R2DBC, the https://github.com/spring-projects-experimental/r2dbc-micrometer-spring-boot[Spring Boot Auto Configuration for R2DBC Observation] creates observations for R2DBC query invocations.
|
||||
|
||||
[[actuator.observability.common-key-values]]
|
||||
=== Common Key-Values
|
||||
Common key-values are generally used for dimensional drill-down on the operating environment, such as host, instance, region, stack, and others.
|
||||
Commons key-values are applied to all observations as low cardinality key-values and can be configured, as the following example shows:
|
||||
|
||||
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
|
||||
----
|
||||
management:
|
||||
observations:
|
||||
key-values:
|
||||
region: "us-east-1"
|
||||
stack: "prod"
|
||||
----
|
||||
|
||||
The preceding example adds `region` and `stack` key-values to all observations with a value of `us-east-1` and `prod`, respectively.
|
||||
|
||||
The next sections will provide more details about logging, metrics and traces.
|
||||
|
|
|
|||
Loading…
Reference in New Issue