diff --git a/concurrency-tests/build.gradle b/concurrency-tests/build.gradle index 6870dd985e..7d0c6620ef 100644 --- a/concurrency-tests/build.gradle +++ b/concurrency-tests/build.gradle @@ -11,7 +11,7 @@ dependencies { } jcstress { - jcstressDependency 'org.openjdk.jcstress:jcstress-core:0.16' + libs.jcstressCore verbose = true } diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index c095d0cf9b..12246526ee 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -2,8 +2,8 @@ * xref:installing.adoc[Installing] * xref:concepts.adoc[Concepts] ** xref:concepts/implementations.adoc[Supported Monitoring Systems] -** xref:concepts/registry.adoc[Registry] ** xref:concepts/meters.adoc[Meters] +** xref:concepts/registry.adoc[Registry] ** xref:concepts/naming.adoc[Naming Meters] ** xref:concepts/meter-filters.adoc[Meter Filters] ** xref:concepts/rate-aggregation.adoc[Rate Aggregation] diff --git a/docs/modules/ROOT/pages/concepts/meters.adoc b/docs/modules/ROOT/pages/concepts/meters.adoc index 911a5685a1..a29770e1ad 100644 --- a/docs/modules/ROOT/pages/concepts/meters.adoc +++ b/docs/modules/ROOT/pages/concepts/meters.adoc @@ -1,6 +1,11 @@ [[meters]] = Meters +A `Meter` is the interface for collecting a set of measurements (which we individually call metrics) about your application. + Micrometer supports a set of `Meter` primitives, including `Timer`, `Counter`, `Gauge`, `DistributionSummary`, `LongTaskTimer`, `FunctionCounter`, `FunctionTimer`, and `TimeGauge`. Different meter types result in a different number of time series metrics. For example, while there is a single metric that represents a `Gauge`, a `Timer` measures both the count of timed events and the total time of all timed events. +TIP: Recording a measurement for a `Meter` is expected to be a relatively cheap operation and should not throw any exception. +If the xref:./registry.adoc[registry] supports publishing metrics to a monitoring system, this is done in a separate thread snd should not affect recording metrics. + A meter is uniquely identified by its name and dimensions. We use the terms, "`dimensions`" and "`tags,`" interchangeably, and the Micrometer interface is `Tag` simply because it is shorter. As a general rule, it should be possible to use the name as a pivot. Dimensions let a particular named metric be sliced to drill down and reason about the data. This means that, if only the name is selected, you can drill down by using other dimensions and reason about the value being shown. diff --git a/docs/modules/ROOT/pages/concepts/registry.adoc b/docs/modules/ROOT/pages/concepts/registry.adoc index eae8732d6d..476f2d9e72 100644 --- a/docs/modules/ROOT/pages/concepts/registry.adoc +++ b/docs/modules/ROOT/pages/concepts/registry.adoc @@ -1,7 +1,7 @@ [[registry]] = Registry -A `Meter` is the interface for collecting a set of measurements (which we individually call metrics) about your application. Meters in Micrometer are created from and held in a `MeterRegistry`. Each supported monitoring system has an implementation of `MeterRegistry`. How a registry is created varies for each implementation. +Meters in Micrometer are created from and held in a `MeterRegistry`. Each supported monitoring system has an implementation of `MeterRegistry`. How a registry is created varies for each implementation. Micrometer includes a `SimpleMeterRegistry` that holds the latest value of each meter in memory and does not export the data anywhere. If you do not yet have a preferred monitoring system, you can get started playing with metrics by using the simple registry: diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/MeterRegistry.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/MeterRegistry.java index 0cc5776a64..11974d4324 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/MeterRegistry.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/MeterRegistry.java @@ -103,8 +103,8 @@ public abstract class MeterRegistry { /** * write/remove guarded by meterMapLock, read in - * {@link this#getOrCreateMeter(DistributionStatisticConfig, BiFunction, Id, - * Function)} is unguarded + * {@link #getOrCreateMeter(DistributionStatisticConfig, BiFunction, Id, Function)} is + * unguarded */ private final Map preFilterIdToMeterMap = new HashMap<>(); @@ -755,15 +755,16 @@ public Meter remove(Meter.Id mappedId) { if (meterMap.containsKey(mappedId)) { synchronized (meterMapLock) { final Meter removedMeter = meterMap.remove(mappedId); - Iterator> iterator = preFilterIdToMeterMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry nextEntry = iterator.next(); - if (nextEntry.getValue().equals(removedMeter)) { - stalePreFilterIds.remove(nextEntry.getKey()); - iterator.remove(); - } - } if (removedMeter != null) { + Iterator> iterator = preFilterIdToMeterMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry nextEntry = iterator.next(); + if (nextEntry.getValue().equals(removedMeter)) { + stalePreFilterIds.remove(nextEntry.getKey()); + iterator.remove(); + } + } + Set synthetics = syntheticAssociations.remove(mappedId); if (synthetics != null) { for (Id synthetic : synthetics) { diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/MeterRegistryTest.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/MeterRegistryTest.java index e687c276e4..25246d662b 100644 --- a/micrometer-core/src/test/java/io/micrometer/core/instrument/MeterRegistryTest.java +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/MeterRegistryTest.java @@ -272,7 +272,6 @@ void differentPreFilterIdsMapToSameIdWithStaleId() { assertThat(c1).isSameAs(c2); assertThat(registry.remove(c1)).isSameAs(c2); - assertThat(registry.remove(c2)).isNull(); assertThat(registry.getMeters()).isEmpty(); } @@ -314,6 +313,7 @@ void removingStaleMeterRemovesItFromAllInternalState() { Counter c1 = registry.counter("counter"); // make c1 marked as stale registry.config().commonTags("common", "tag"); + assertThat(registry._getStalePreFilterIds()).hasSize(1); registry.remove(c1.getId()); assertThat(registry.getMeters()).isEmpty(); @@ -338,6 +338,7 @@ void unchangedStaleMeterShouldBeUnmarked() { Counter c1 = registry.counter("counter"); // make c1 stale registry.config().meterFilter(MeterFilter.ignoreTags("abc")); + assertThat(registry._getStalePreFilterIds()).hasSize(1); // this should cause c1 (== c2) to be unmarked as stale Counter c2 = registry.counter("counter"); @@ -347,7 +348,7 @@ void unchangedStaleMeterShouldBeUnmarked() { assertThat(registry._getPreFilterIdToMeterMap()).hasSize(1); assertThat(registry._getStalePreFilterIds()) .describedAs("If the meter-filter doesn't alter the meter creation, meters are never unmarked " - + "from staleness and we end-up paying the additional cost everytime") + + "from staleness and we end up paying the additional cost every time") .isEmpty(); }