From d22363242cf56e5415201a9ca3748310ecf0ecfe Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 25 Jan 2024 15:30:01 +0100 Subject: [PATCH 1/3] Adds Observation Granularity - introduces observation levels (same as in logging) - extends the current API to allow passing of ObservationLevel fixes gh-3442 --- .../ObservationConfiguringTests.java | 8 +- .../java/io/micrometer/observation/Level.java | 28 +++ .../observation/NoopObservation.java | 2 +- .../micrometer/observation/Observation.java | 216 +++++++++++++++++- .../observation/ObservationRegistry.java | 58 ++++- .../PassthroughNoopObservation.java | 44 ++++ .../observation/ObservationTests.java | 21 +- .../ObservationTextPublisherTests.java | 2 +- 8 files changed, 358 insertions(+), 21 deletions(-) create mode 100644 micrometer-observation/src/main/java/io/micrometer/observation/Level.java create mode 100644 micrometer-observation/src/main/java/io/micrometer/observation/PassthroughNoopObservation.java diff --git a/docs/src/test/java/io/micrometer/docs/observation/ObservationConfiguringTests.java b/docs/src/test/java/io/micrometer/docs/observation/ObservationConfiguringTests.java index 90c06d0444..5f9e17ae31 100644 --- a/docs/src/test/java/io/micrometer/docs/observation/ObservationConfiguringTests.java +++ b/docs/src/test/java/io/micrometer/docs/observation/ObservationConfiguringTests.java @@ -76,10 +76,12 @@ void observation_config_customization() { .observationHandler(new DefaultMeterObservationHandler(meterRegistry)); // Observation will be ignored because of the name - then(Observation.start("to.ignore", () -> new MyContext("don't ignore"), registry)).isSameAs(Observation.NOOP); + Observation ignoredBecauseOfName = Observation.start("to.ignore", () -> new MyContext("don't ignore"), + registry); + then(ignoredBecauseOfName.isNoop()).isTrue(); // Observation will be ignored because of the entries in MyContext - then(Observation.start("not.to.ignore", () -> new MyContext("user to ignore"), registry)) - .isSameAs(Observation.NOOP); + Observation notToIgnore = Observation.start("not.to.ignore", () -> new MyContext("user to ignore"), registry); + then(notToIgnore.isNoop()).isTrue(); // Observation will not be ignored... MyContext myContext = new MyContext("user not to ignore"); diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/Level.java b/micrometer-observation/src/main/java/io/micrometer/observation/Level.java new file mode 100644 index 0000000000..91c893811b --- /dev/null +++ b/micrometer-observation/src/main/java/io/micrometer/observation/Level.java @@ -0,0 +1,28 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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 io.micrometer.observation; + +/** + * Observation Level. + * + * @author Marcin Grzejszczak + * @since 1.13.0 + */ +public enum Level { + + ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF + +} diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/NoopObservation.java b/micrometer-observation/src/main/java/io/micrometer/observation/NoopObservation.java index 27e91f599b..413f555772 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/NoopObservation.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/NoopObservation.java @@ -27,7 +27,7 @@ * @author Marcin Grzejszczak * @since 1.10.0 */ -final class NoopObservation implements Observation { +class NoopObservation implements Observation { private static final Context CONTEXT = new Context(); diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java b/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java index d3801305d3..11fb802a21 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java @@ -90,6 +90,60 @@ static Observation start(String name, Supplier contextSup return createNotStarted(name, contextSupplier, registry).start(); } + /** + * Create and start an {@link Observation} with the given name. All Observations of + * the same type must share the same name. + *

+ * When no registry is passed or the observation is + * {@link ObservationRegistry.ObservationConfig#observationPredicate(ObservationPredicate) + * not applicable}, a no-op observation will be returned. + * @param name name of the observation + * @param level observation level + * @param registry observation registry + * @return a started observation + * @since 1.13.0 + */ + static Observation start(String name, ObservationLevel level, @Nullable ObservationRegistry registry) { + return start(name, Context::new, level, registry); + } + + /** + * Creates and starts an {@link Observation}. When the {@link ObservationRegistry} is + * null or the no-op registry, this fast returns a no-op {@link Observation} and skips + * the creation of the {@link Observation.Context}. This check avoids unnecessary + * {@link Observation.Context} creation, which is why it takes a {@link Supplier} for + * the context rather than the context directly. If the observation is not enabled + * (see + * {@link ObservationRegistry.ObservationConfig#observationPredicate(ObservationPredicate) + * ObservationConfig#observationPredicate}), a no-op observation will also be + * returned. + * @param name name of the observation + * @param contextSupplier mutable context supplier + * @param level observation level + * @param registry observation registry + * @return started observation + * @since 1.13.0 + */ + static Observation start(String name, Supplier contextSupplier, ObservationLevel level, + @Nullable ObservationRegistry registry) { + return createNotStarted(name, contextSupplier, level, registry).start(); + } + + /** + * Creates but does not start an {@link Observation}. Remember to call + * {@link Observation#start()} when you want the measurements to start. When no + * registry is passed or observation is not applicable will return a no-op + * observation. + * @param name name of the observation + * @param level observation level + * @param registry observation registry + * @return created but not started observation + * @since 1.13.0 + */ + static Observation createNotStarted(String name, ObservationLevel level, @Nullable ObservationRegistry registry) { + return createNotStarted(name, Context::new, level, registry); + } + /** * Creates but does not start an {@link Observation}. Remember to call * {@link Observation#start()} when you want the measurements to start. When no @@ -122,13 +176,38 @@ static Observation createNotStarted(String name, @Nullable ObservationRegistry r */ static Observation createNotStarted(String name, Supplier contextSupplier, @Nullable ObservationRegistry registry) { + return createNotStarted(name, contextSupplier, null, registry); + } + + /** + * Creates but does not start an {@link Observation}. Remember to call + * {@link Observation#start()} when you want the measurements to start. When the + * {@link ObservationRegistry} is null or the no-op registry, this fast returns a + * no-op {@link Observation} and skips the creation of the + * {@link Observation.Context}. This check avoids unnecessary + * {@link Observation.Context} creation, which is why it takes a {@link Supplier} for + * the context rather than the context directly. If the observation is not enabled + * (see + * {@link ObservationRegistry.ObservationConfig#observationPredicate(ObservationPredicate) + * ObservationConfig#observationPredicate}), a no-op observation will also be + * returned. + * @param name name of the observation + * @param contextSupplier supplier for mutable context + * @param level observation level + * @param registry observation registry + * @return created but not started observation + * @since 1.13.0 + */ + static Observation createNotStarted(String name, Supplier contextSupplier, + @Nullable ObservationLevel level, @Nullable ObservationRegistry registry) { if (registry == null || registry.isNoop()) { return NOOP; } Context context = contextSupplier.get(); context.setParentFromCurrentObservation(registry); + context.setLevel(level != null ? level : null); if (!registry.observationConfig().isObservationEnabled(name, context)) { - return NOOP; + return new PassthroughNoopObservation(context.getParentObservation()); } return new SimpleObservation(name, registry, context); } @@ -178,7 +257,7 @@ static Observation createNotStarted(@Nullable ObservationCon convention = registry.observationConfig().getObservationConvention(context, defaultConvention); } if (!registry.observationConfig().isObservationEnabled(convention.getName(), context)) { - return NOOP; + return new PassthroughNoopObservation(context.getParentObservation()); } return new SimpleObservation(convention, registry, context); } @@ -316,7 +395,7 @@ static Observation createNotStarted(ObservationConvention T context = contextSupplier.get(); context.setParentFromCurrentObservation(registry); if (!registry.observationConfig().isObservationEnabled(observationConvention.getName(), context)) { - return NOOP; + return new PassthroughNoopObservation(context.getParentObservation()); } return new SimpleObservation(observationConvention, registry, context); } @@ -417,7 +496,7 @@ default Observation highCardinalityKeyValues(KeyValues keyValues) { * @return {@code true} when this is a no-op observation */ default boolean isNoop() { - return this == NOOP; + return this == NOOP || this instanceof NoopObservation; } /** @@ -923,7 +1002,10 @@ class Context implements ContextView { private Throwable error; @Nullable - private ObservationView parentObservation; + private ObservationView parentObservationView; + + @Nullable + private ObservationLevel level; private final Map lowCardinalityKeyValues = new LinkedHashMap<>(); @@ -970,7 +1052,7 @@ public void setContextualName(@Nullable String contextualName) { */ @Nullable public ObservationView getParentObservation() { - return parentObservation; + return parentObservationView; } /** @@ -978,7 +1060,7 @@ public ObservationView getParentObservation() { * @param parentObservation parent observation to set */ public void setParentObservation(@Nullable ObservationView parentObservation) { - this.parentObservation = parentObservation; + this.parentObservationView = parentObservation; } /** @@ -987,7 +1069,7 @@ public void setParentObservation(@Nullable ObservationView parentObservation) { * @param registry the {@link ObservationRegistry} in using */ void setParentFromCurrentObservation(ObservationRegistry registry) { - if (this.parentObservation == null) { + if (this.parentObservationView == null) { Observation currentObservation = registry.getCurrentObservation(); if (currentObservation != null) { setParentObservation(currentObservation); @@ -1232,12 +1314,21 @@ public KeyValues getAllKeyValues() { return getLowCardinalityKeyValues().and(getHighCardinalityKeyValues()); } + @Nullable + public ObservationLevel getLevel() { + return level; + } + + void setLevel(ObservationLevel level) { + this.level = level; + } + @Override public String toString() { return "name='" + name + '\'' + ", contextualName='" + contextualName + '\'' + ", error='" + error + '\'' + ", lowCardinalityKeyValues=" + toString(getLowCardinalityKeyValues()) + ", highCardinalityKeyValues=" + toString(getHighCardinalityKeyValues()) + ", map=" + toString(map) - + ", parentObservation=" + parentObservation; + + ", parentObservation=" + parentObservationView + ", observationLevel=" + level; } private String toString(KeyValues keyValues) { @@ -1452,6 +1543,14 @@ default T getOrDefault(Object key, Supplier defaultObjectSupplier) { @NonNull KeyValues getAllKeyValues(); + /** + * Returns the observation level. + * @return observation level + */ + default Level getObservationLevel() { + return Level.ALL; + } + } /** @@ -1487,4 +1586,103 @@ interface CheckedFunction { } + /** + * Mapping of {@link Level} to {@link Class}. + * + * @author Marcin Grzejszczak + * @since 1.13.0 + */ + class ObservationLevel { + + private final Level level; + + private final Class clazz; + + public ObservationLevel(Level level, Class clazz) { + this.level = level; + this.clazz = clazz; + } + + public Level getLevel() { + return level; + } + + public Class getClazz() { + return clazz; + } + + /** + * Sets {@link Level#ALL} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel all(Class clazz) { + return new ObservationLevel(Level.ALL, clazz); + } + + /** + * Sets {@link Level#TRACE} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel trace(Class clazz) { + return new ObservationLevel(Level.TRACE, clazz); + } + + /** + * Sets {@link Level#DEBUG} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel debug(Class clazz) { + return new ObservationLevel(Level.DEBUG, clazz); + } + + /** + * Sets {@link Level#INFO} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel info(Class clazz) { + return new ObservationLevel(Level.INFO, clazz); + } + + /** + * Sets {@link Level#WARN} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel warn(Class clazz) { + return new ObservationLevel(Level.WARN, clazz); + } + + /** + * Sets {@link Level#ERROR} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel error(Class clazz) { + return new ObservationLevel(Level.ERROR, clazz); + } + + /** + * Sets {@link Level#FATAL} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel fatal(Class clazz) { + return new ObservationLevel(Level.FATAL, clazz); + } + + /** + * Sets {@link Level#OFF} for observation of the given classs. + * @param clazz class to observe + * @return observation level + */ + public static ObservationLevel off(Class clazz) { + return new ObservationLevel(Level.OFF, clazz); + } + + } + } diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java b/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java index 642fb90d62..82aa698694 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java @@ -17,11 +17,14 @@ import io.micrometer.common.lang.Nullable; -import java.util.Collection; -import java.util.List; -import java.util.Objects; +import io.micrometer.observation.Observation.ObservationLevel; + +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; +import java.util.stream.Collectors; /** * Implementations of this interface are responsible for managing state of an @@ -102,6 +105,8 @@ class ObservationConfig { private final List observationFilters = new CopyOnWriteArrayList<>(); + private final Map observationLevels = new ConcurrentHashMap<>(); + /** * Register a handler for the {@link Observation observations}. * @param handler handler to add to the current configuration @@ -149,6 +154,27 @@ public ObservationConfig observationConvention(GlobalObservationConvention ob return this; } + /** + * Sets an observation level for the given package name. + * @param packageName observation package name + * @param level observation level + * @return This configuration instance + */ + public ObservationConfig observationLevel(String packageName, Level level) { + this.observationLevels.put(packageName, level); + return this; + } + + /** + * Sets observation levels. + * @param levels observation levels (package to level mappings) + * @return This configuration instance + */ + public ObservationConfig observationLevels(Map levels) { + this.observationLevels.putAll(levels); + return this; + } + /** * Finds an {@link ObservationConvention} for the given * {@link Observation.Context}. @@ -181,6 +207,32 @@ boolean isObservationEnabled(String name, @Nullable Observation.Context context) return false; } } + if (context != null) { + ObservationLevel level = context.getLevel(); + if (level == null) { + return true; + } + Class clazz = level.getClazz(); + String classToObserveFqn = clazz.getCanonicalName(); + String classToObservePackage = clazz.getPackage().getName(); + // a.b.c - 2 + // a.b.c.D - 3 + // a.b - 1 + // we sort by string length, that means that we will find the closest + // matching first + List> sortedLevels = this.observationLevels.entrySet() + .stream() + .sorted(Collections.reverseOrder(Comparator.comparingInt(value -> value.getKey().length()))) + .collect(Collectors.toList()); + for (Entry levelEntry : sortedLevels) { + if (classToObserveFqn.equals(levelEntry.getKey()) + || classToObservePackage.contains(levelEntry.getKey())) { + // exact or partial match + // e.g. ctx has INFO (3), configured is DEBUG (2) + return level.getLevel().ordinal() >= levelEntry.getValue().ordinal(); + } + } + } return true; } diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/PassthroughNoopObservation.java b/micrometer-observation/src/main/java/io/micrometer/observation/PassthroughNoopObservation.java new file mode 100644 index 0000000000..bf82d6bcf2 --- /dev/null +++ b/micrometer-observation/src/main/java/io/micrometer/observation/PassthroughNoopObservation.java @@ -0,0 +1,44 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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 io.micrometer.observation; + +import io.micrometer.common.lang.Nullable; + +/** + * No-op implementation of {@link Observation} that passes through to the parent + * observation. + * + * @author Marcin Grzejszczak + * @since 1.13.0 + */ +final class PassthroughNoopObservation extends NoopObservation { + + private final @Nullable ObservationView parentObservation; + + PassthroughNoopObservation(@Nullable ObservationView parentObservation) { + this.parentObservation = parentObservation; + } + + @Override + public ContextView getContextView() { + if (this.parentObservation != null) { + // we pass through to the parent + return this.parentObservation.getContextView(); + } + return super.getContextView(); + } + +} diff --git a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java index 7f7170ace8..d491fb9113 100644 --- a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java +++ b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java @@ -18,6 +18,7 @@ import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.Observation.ObservationLevel; import org.awaitility.Awaitility; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -71,7 +72,19 @@ void notMatchingObservationPredicateShouldResultInNoopObservation() { Observation observation = Observation.createNotStarted("foo", registry); - assertThat(observation).isSameAs(Observation.NOOP); + assertThat(observation).isInstanceOf(PassthroughNoopObservation.class); + } + + @Test + void notMatchingObservationLevelShouldResultInPassthroughObservation() { + registry.observationConfig().observationHandler(context -> true); + registry.observationConfig().observationPredicate((s, context) -> true); + registry.observationConfig().observationLevel("io.micrometer", Level.TRACE); + registry.observationConfig().observationLevel("io.micrometer.observation", Level.ERROR); + + Observation observation = Observation.createNotStarted("foo", ObservationLevel.debug(getClass()), registry); + + assertThat(observation).isInstanceOf(PassthroughNoopObservation.class); } @Test @@ -81,7 +94,7 @@ void matchingPredicateAndHandlerShouldNotResultInNoopObservation() { Observation observation = Observation.createNotStarted("foo", registry); - assertThat(observation).isNotSameAs(Observation.NOOP); + assertThat(observation).isNotInstanceOf(NoopObservation.class); } @Test @@ -91,11 +104,11 @@ void usingParentObservationToMatchPredicate() { .observationPredicate((s, context) -> !s.equals("child") || context.getParentObservation() != null); Observation childWithoutParent = Observation.createNotStarted("child", registry); - assertThat(childWithoutParent).isSameAs(Observation.NOOP); + assertThat(childWithoutParent).isInstanceOf(PassthroughNoopObservation.class); Observation childWithParent = Observation.createNotStarted("parent", registry) .observe(() -> Observation.createNotStarted("child", registry)); - assertThat(childWithParent).isNotSameAs(Observation.NOOP); + assertThat(childWithParent).isNotInstanceOf(NoopObservation.class); } @Test diff --git a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTextPublisherTests.java b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTextPublisherTests.java index 511d86fc94..86d80b465d 100644 --- a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTextPublisherTests.java +++ b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTextPublisherTests.java @@ -30,7 +30,7 @@ */ class ObservationTextPublisherTests { - private static final String CONTEXT_TOSTRING = "name='testName', contextualName='testContextualName', error='java.io.IOException: simulated', lowCardinalityKeyValues=[lcTag='foo'], highCardinalityKeyValues=[hcTag='bar'], map=[contextKey='contextValue'], parentObservation=null"; + private static final String CONTEXT_TOSTRING = "name='testName', contextualName='testContextualName', error='java.io.IOException: simulated', lowCardinalityKeyValues=[lcTag='foo'], highCardinalityKeyValues=[hcTag='bar'], map=[contextKey='contextValue'], parentObservation=null, observationLevel=null"; private final TestConsumer consumer = new TestConsumer(); From 64a409dd8e460c4b34468f77728ecac5c7466829 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 30 Jan 2024 17:04:08 +0100 Subject: [PATCH 2/3] Polish --- .../micrometer/observation/Observation.java | 52 +++++++------------ .../observation/ObservationRegistry.java | 19 ++----- .../observation/ObservationTests.java | 5 +- 3 files changed, 25 insertions(+), 51 deletions(-) diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java b/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java index 11fb802a21..a7586fd29f 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java @@ -204,6 +204,9 @@ static Observation createNotStarted(String name, Supplier return NOOP; } Context context = contextSupplier.get(); + if (context.getName() == null) { + context.setName(name); + } context.setParentFromCurrentObservation(registry); context.setLevel(level != null ? level : null); if (!registry.observationConfig().isObservationEnabled(name, context)) { @@ -1596,91 +1599,76 @@ class ObservationLevel { private final Level level; - private final Class clazz; - - public ObservationLevel(Level level, Class clazz) { + public ObservationLevel(Level level) { this.level = level; - this.clazz = clazz; } public Level getLevel() { return level; } - public Class getClazz() { - return clazz; - } - /** * Sets {@link Level#ALL} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel all(Class clazz) { - return new ObservationLevel(Level.ALL, clazz); + public static ObservationLevel all() { + return new ObservationLevel(Level.ALL); } /** * Sets {@link Level#TRACE} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel trace(Class clazz) { - return new ObservationLevel(Level.TRACE, clazz); + public static ObservationLevel trace() { + return new ObservationLevel(Level.TRACE); } /** * Sets {@link Level#DEBUG} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel debug(Class clazz) { - return new ObservationLevel(Level.DEBUG, clazz); + public static ObservationLevel debug() { + return new ObservationLevel(Level.DEBUG); } /** * Sets {@link Level#INFO} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel info(Class clazz) { - return new ObservationLevel(Level.INFO, clazz); + public static ObservationLevel info() { + return new ObservationLevel(Level.INFO); } /** * Sets {@link Level#WARN} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel warn(Class clazz) { - return new ObservationLevel(Level.WARN, clazz); + public static ObservationLevel warn() { + return new ObservationLevel(Level.WARN); } /** * Sets {@link Level#ERROR} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel error(Class clazz) { - return new ObservationLevel(Level.ERROR, clazz); + public static ObservationLevel error() { + return new ObservationLevel(Level.ERROR); } /** * Sets {@link Level#FATAL} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel fatal(Class clazz) { - return new ObservationLevel(Level.FATAL, clazz); + public static ObservationLevel fatal() { + return new ObservationLevel(Level.FATAL); } /** * Sets {@link Level#OFF} for observation of the given classs. - * @param clazz class to observe * @return observation level */ - public static ObservationLevel off(Class clazz) { - return new ObservationLevel(Level.OFF, clazz); + public static ObservationLevel off() { + return new ObservationLevel(Level.OFF); } } diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java b/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java index 82aa698694..dd129b9a2e 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java @@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; -import java.util.stream.Collectors; /** * Implementations of this interface are responsible for managing state of an @@ -212,21 +211,9 @@ boolean isObservationEnabled(String name, @Nullable Observation.Context context) if (level == null) { return true; } - Class clazz = level.getClazz(); - String classToObserveFqn = clazz.getCanonicalName(); - String classToObservePackage = clazz.getPackage().getName(); - // a.b.c - 2 - // a.b.c.D - 3 - // a.b - 1 - // we sort by string length, that means that we will find the closest - // matching first - List> sortedLevels = this.observationLevels.entrySet() - .stream() - .sorted(Collections.reverseOrder(Comparator.comparingInt(value -> value.getKey().length()))) - .collect(Collectors.toList()); - for (Entry levelEntry : sortedLevels) { - if (classToObserveFqn.equals(levelEntry.getKey()) - || classToObservePackage.contains(levelEntry.getKey())) { + String observationName = context.getName(); + for (Entry levelEntry : this.observationLevels.entrySet()) { + if (levelEntry.getKey().equalsIgnoreCase(observationName)) { // exact or partial match // e.g. ctx has INFO (3), configured is DEBUG (2) return level.getLevel().ordinal() >= levelEntry.getValue().ordinal(); diff --git a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java index d491fb9113..301aaab24b 100644 --- a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java +++ b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java @@ -79,10 +79,9 @@ void notMatchingObservationPredicateShouldResultInNoopObservation() { void notMatchingObservationLevelShouldResultInPassthroughObservation() { registry.observationConfig().observationHandler(context -> true); registry.observationConfig().observationPredicate((s, context) -> true); - registry.observationConfig().observationLevel("io.micrometer", Level.TRACE); - registry.observationConfig().observationLevel("io.micrometer.observation", Level.ERROR); + registry.observationConfig().observationLevel("foo", Level.ERROR); - Observation observation = Observation.createNotStarted("foo", ObservationLevel.debug(getClass()), registry); + Observation observation = Observation.createNotStarted("foo", ObservationLevel.debug(), registry); assertThat(observation).isInstanceOf(PassthroughNoopObservation.class); } From 2d318e9581c756eb9b986840e1b69450d15c0507 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Wed, 7 Feb 2024 10:42:40 +0100 Subject: [PATCH 3/3] Updated levels --- .../java/io/micrometer/observation/Level.java | 2 +- .../micrometer/observation/Observation.java | 52 ++++--------------- .../observation/ObservationRegistry.java | 10 ++-- .../observation/ObservationTests.java | 4 +- 4 files changed, 18 insertions(+), 50 deletions(-) diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/Level.java b/micrometer-observation/src/main/java/io/micrometer/observation/Level.java index 91c893811b..fd215f4e3f 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/Level.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/Level.java @@ -23,6 +23,6 @@ */ public enum Level { - ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF + FULL, DETAILED, BASIC, OFF } diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java b/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java index a7586fd29f..f0c0dc4701 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/Observation.java @@ -1551,7 +1551,7 @@ default T getOrDefault(Object key, Supplier defaultObjectSupplier) { * @return observation level */ default Level getObservationLevel() { - return Level.ALL; + return Level.FULL; } } @@ -1608,59 +1608,27 @@ public Level getLevel() { } /** - * Sets {@link Level#ALL} for observation of the given classs. + * Sets {@link Level#FULL} for observation of the given classs. * @return observation level */ - public static ObservationLevel all() { - return new ObservationLevel(Level.ALL); + public static ObservationLevel full() { + return new ObservationLevel(Level.FULL); } /** - * Sets {@link Level#TRACE} for observation of the given classs. + * Sets {@link Level#BASIC} for observation of the given classs. * @return observation level */ - public static ObservationLevel trace() { - return new ObservationLevel(Level.TRACE); + public static ObservationLevel basic() { + return new ObservationLevel(Level.BASIC); } /** - * Sets {@link Level#DEBUG} for observation of the given classs. + * Sets {@link Level#DETAILED} for observation of the given classs. * @return observation level */ - public static ObservationLevel debug() { - return new ObservationLevel(Level.DEBUG); - } - - /** - * Sets {@link Level#INFO} for observation of the given classs. - * @return observation level - */ - public static ObservationLevel info() { - return new ObservationLevel(Level.INFO); - } - - /** - * Sets {@link Level#WARN} for observation of the given classs. - * @return observation level - */ - public static ObservationLevel warn() { - return new ObservationLevel(Level.WARN); - } - - /** - * Sets {@link Level#ERROR} for observation of the given classs. - * @return observation level - */ - public static ObservationLevel error() { - return new ObservationLevel(Level.ERROR); - } - - /** - * Sets {@link Level#FATAL} for observation of the given classs. - * @return observation level - */ - public static ObservationLevel fatal() { - return new ObservationLevel(Level.FATAL); + public static ObservationLevel detailed() { + return new ObservationLevel(Level.DETAILED); } /** diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java b/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java index dd129b9a2e..86b531c31e 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/ObservationRegistry.java @@ -154,19 +154,19 @@ public ObservationConfig observationConvention(GlobalObservationConvention ob } /** - * Sets an observation level for the given package name. - * @param packageName observation package name + * Sets an observation level for the given observation name. + * @param observationName observation name * @param level observation level * @return This configuration instance */ - public ObservationConfig observationLevel(String packageName, Level level) { - this.observationLevels.put(packageName, level); + public ObservationConfig observationLevel(String observationName, Level level) { + this.observationLevels.put(observationName, level); return this; } /** * Sets observation levels. - * @param levels observation levels (package to level mappings) + * @param levels observation levels (observation name to level mappings) * @return This configuration instance */ public ObservationConfig observationLevels(Map levels) { diff --git a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java index 301aaab24b..e1209b10d1 100644 --- a/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java +++ b/micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java @@ -79,9 +79,9 @@ void notMatchingObservationPredicateShouldResultInNoopObservation() { void notMatchingObservationLevelShouldResultInPassthroughObservation() { registry.observationConfig().observationHandler(context -> true); registry.observationConfig().observationPredicate((s, context) -> true); - registry.observationConfig().observationLevel("foo", Level.ERROR); + registry.observationConfig().observationLevel("foo", Level.BASIC); - Observation observation = Observation.createNotStarted("foo", ObservationLevel.debug(), registry); + Observation observation = Observation.createNotStarted("foo", ObservationLevel.detailed(), registry); assertThat(observation).isInstanceOf(PassthroughNoopObservation.class); }