diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/observation/DefaultMeterObservationHandler.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/observation/DefaultMeterObservationHandler.java index a21a37ae41..e5c5211da7 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/observation/DefaultMeterObservationHandler.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/observation/DefaultMeterObservationHandler.java @@ -16,12 +16,17 @@ package io.micrometer.core.instrument.observation; import io.micrometer.common.KeyValue; +import io.micrometer.common.KeyValues; import io.micrometer.core.instrument.*; +import io.micrometer.core.instrument.Timer; import io.micrometer.observation.Observation; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Handler for {@link Timer.Sample} and {@link Counter}. @@ -45,6 +50,8 @@ public class DefaultMeterObservationHandler implements MeterObservationHandler, Tags> tagCache = new ConcurrentHashMap<>(); + /** * Creates the handler with the default configuration. * @param meterRegistry the MeterRegistry to use @@ -71,8 +78,9 @@ public DefaultMeterObservationHandler(MeterRegistry meterRegistry, IgnoredMeters @Override public void onStart(Observation.Context context) { if (shouldCreateLongTaskTimer) { - LongTaskTimer.Sample longTaskSample = LongTaskTimer.builder(context.getName() + ".active") - .tags(createTags(context)) + String name = context.getName() + ".active"; + LongTaskTimer.Sample longTaskSample = LongTaskTimer.builder(name) + .tags(getOrCreateTags(name, context.getLowCardinalityKeyValues())) .register(meterRegistry) .start(); context.put(LongTaskTimer.Sample.class, longTaskSample); @@ -84,10 +92,11 @@ public void onStart(Observation.Context context) { @Override public void onStop(Observation.Context context) { - List tags = createTags(context); - tags.add(Tag.of("error", getErrorValue(context))); Timer.Sample sample = context.getRequired(Timer.Sample.class); - sample.stop(Timer.builder(context.getName()).tags(tags).register(this.meterRegistry)); + String name = context.getName(); + sample.stop(Timer.builder(name) + .tags(getOrCreateTags(name, context.getLowCardinalityKeyValues(), getErrorValue(context))) + .register(this.meterRegistry)); if (shouldCreateLongTaskTimer) { LongTaskTimer.Sample longTaskSample = context.getRequired(LongTaskTimer.Sample.class); @@ -97,8 +106,9 @@ public void onStop(Observation.Context context) { @Override public void onEvent(Observation.Event event, Observation.Context context) { - Counter.builder(context.getName() + "." + event.getName()) - .tags(createTags(context)) + String name = context.getName() + "." + event.getName(); + Counter.builder(name) + .tags(getOrCreateTags(name, context.getLowCardinalityKeyValues())) .register(meterRegistry) .increment(); } @@ -108,12 +118,25 @@ private String getErrorValue(Observation.Context context) { return error != null ? error.getClass().getSimpleName() : "none"; } - private List createTags(Observation.Context context) { - List tags = new ArrayList<>(); - for (KeyValue keyValue : context.getLowCardinalityKeyValues()) { - tags.add(Tag.of(keyValue.getKey(), keyValue.getValue())); - } - return tags; + private Tags getOrCreateTags(String name, KeyValues lowCardinalityKeyValues) { + return getOrCreateTags(name, lowCardinalityKeyValues, null); + } + + private Tags getOrCreateTags(String name, KeyValues lowCardinalityKeyValues, String errorValue) { + Map.Entry key = new AbstractMap.SimpleEntry<>(name, lowCardinalityKeyValues); + + return tagCache.computeIfAbsent(key, k -> { + List tagList = new ArrayList<>(); + for (KeyValue keyValue : lowCardinalityKeyValues) { + tagList.add(Tag.of(keyValue.getKey(), keyValue.getValue())); + } + + if (errorValue != null) { + tagList.add(Tag.of("error", errorValue)); + } + + return Tags.of(tagList); + }); } /**