From 8648704db0e41208df8d15f424a716024c661ca9 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 17 Sep 2026 13:50:48 +0200 Subject: [PATCH 1/5] docs(java): Add Micrometer integration guide Document plain Java and Spring Boot setup for exporting Micrometer metrics to Sentry, including mappings, polling, filtering, and lifecycle guidance. Co-Authored-By: Claude --- .../java/common/integrations/micrometer.mdx | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 docs/platforms/java/common/integrations/micrometer.mdx diff --git a/docs/platforms/java/common/integrations/micrometer.mdx b/docs/platforms/java/common/integrations/micrometer.mdx new file mode 100644 index 0000000000000..e331a64819b7f --- /dev/null +++ b/docs/platforms/java/common/integrations/micrometer.mdx @@ -0,0 +1,285 @@ +--- +title: Micrometer Integration +description: "Learn how to send Micrometer metrics to Sentry from Java and Spring Boot applications." +--- + +The Sentry Micrometer integration adds Sentry as another destination for metrics recorded through [Micrometer](https://micrometer.io/). It works alongside Prometheus, Datadog, OTLP, and other registries without changing their behavior. + +The integration is available in Sentry Java SDK version `8.58.0` and later. It's built against Micrometer `1.9.17` and tested with the Micrometer versions used by supported Spring Boot 2, 3, and 4 releases. + +## Install + +Add `sentry-micrometer` to the application that records your Micrometer metrics. + + + +The Sentry Spring Boot starters don't include this module automatically. Spring Boot Actuator supplies Micrometer and its automatically registered HTTP server, JVM, process, and logging metrics. Add Actuator if your application doesn't already use it. + +```groovy {tabTitle:Gradle}{filename:build.gradle} +implementation 'io.sentry:sentry-micrometer:{{@inject packages.version('sentry.java.micrometer', '8.58.0') }}' +implementation 'org.springframework.boot:spring-boot-starter-actuator' +``` + +```xml {tabTitle:Maven}{filename:pom.xml} + + io.sentry + sentry-micrometer + {{@inject packages.version('sentry.java.micrometer', '8.58.0') }} + + + org.springframework.boot + spring-boot-starter-actuator + +``` + + + + + +Add Micrometer Core if your application doesn't already include it. Use the Micrometer version managed by your framework or dependency platform when applicable. + +```groovy {tabTitle:Gradle}{filename:build.gradle} +implementation 'io.sentry:sentry-micrometer:{{@inject packages.version('sentry.java.micrometer', '8.58.0') }}' +implementation 'io.micrometer:micrometer-core:MICROMETER_VERSION' +``` + +```xml {tabTitle:Maven}{filename:pom.xml} + + io.sentry + sentry-micrometer + {{@inject packages.version('sentry.java.micrometer', '8.58.0') }} + + + io.micrometer + micrometer-core + MICROMETER_VERSION + +``` + +```scala {tabTitle:SBT}{filename:build.sbt} +libraryDependencies += "io.sentry" % "sentry-micrometer" % "{{@inject packages.version('sentry.java.micrometer', '8.58.0') }}" +libraryDependencies += "io.micrometer" % "micrometer-core" % "MICROMETER_VERSION" +``` + + + +## Configure + +The integration sends metrics through the current Sentry SDK instance. + + + +The Sentry Spring Boot integration initializes the SDK and can add `SentryMeterRegistry` to the application's composite registry. Enable this opt-in integration in your configuration: + +```properties {tabTitle:application.properties}{filename:application.properties} +sentry.micrometer.enabled=true +sentry.micrometer.poll-interval-millis=60000 +``` + +```yaml {tabTitle:application.yml}{filename:application.yml} +sentry: + micrometer: + enabled: true + poll-interval-millis: 60000 +``` + +The polling interval is optional and defaults to 60 seconds. + + + + + +Create a `SentryMeterRegistry` and add it to Micrometer's global registry after initializing Sentry: + +```java {tabTitle:Java}{filename:Main.java} +import io.micrometer.core.instrument.Metrics; +import io.sentry.micrometer.SentryMeterRegistry; + +SentryMeterRegistry sentryRegistry = new SentryMeterRegistry(); +Metrics.addRegistry(sentryRegistry); +``` + +```kotlin {tabTitle:Kotlin}{filename:Main.kt} +import io.micrometer.core.instrument.Metrics +import io.sentry.micrometer.SentryMeterRegistry + +val sentryRegistry = SentryMeterRegistry() +Metrics.addRegistry(sentryRegistry) +``` + +You can also add `SentryMeterRegistry` to an application-owned `CompositeMeterRegistry`. + + + +## Verify + +Record a counter through the `MeterRegistry` your application already uses: + +```java {tabTitle:Java}{filename:CheckoutMetrics.java} +import io.micrometer.core.instrument.MeterRegistry; + +public final class CheckoutMetrics { + private final MeterRegistry registry; + + public CheckoutMetrics(MeterRegistry registry) { + this.registry = registry; + } + + public void recordCompletedOrder(String paymentMethod) { + registry.counter("checkout.completed", "payment_method", paymentMethod).increment(); + } +} +``` + +```kotlin {tabTitle:Kotlin}{filename:CheckoutMetrics.kt} +import io.micrometer.core.instrument.MeterRegistry + +class CheckoutMetrics(private val registry: MeterRegistry) { + fun recordCompletedOrder(paymentMethod: String) { + registry.counter("checkout.completed", "payment_method", paymentMethod).increment() + } +} +``` + +Call `recordCompletedOrder`, then open [Metrics in Sentry](/product/metrics/) and query for `checkout_completed`. The default naming convention converts dots in metric names to underscores. The `payment_method` tag is available as a metric attribute. + +## Metric Mappings + +The registry applies its configured Micrometer `NamingConvention` to metric names, tag keys, and tag values. The default convention converts dots to underscores. + +The registry forwards active meters when your application records them: + +| Micrometer Meter | Sentry Metric | Name | +| --------------------- | ---------------------------- | -------------- | +| `Counter` | Counter increment | Converted name | +| `Timer` | Distribution in milliseconds | Converted name | +| `DistributionSummary` | Distribution | Converted name | + +The registry polls meters that only expose their current or cumulative value every 60 seconds by default: + +| Micrometer Meter | Sentry Metric | Name | +| ------------------------------- | -------------------------------------- | ----------------------------- | +| `Gauge` | Gauge | Converted name | +| `TimeGauge` | Gauge in milliseconds | Converted name | +| `LongTaskTimer` active tasks | Gauge | `${convertedName}.active` | +| `LongTaskTimer` active duration | Gauge in milliseconds | `${convertedName}.duration` | +| `FunctionCounter` | Positive counter delta | Converted name | +| `FunctionTimer` count | Positive counter delta | `${convertedName}.count` | +| `FunctionTimer` total time | Positive counter delta in milliseconds | `${convertedName}.total_time` | + +The first successful poll of a function meter establishes its baseline and sends nothing. Later polls send positive changes. A lower value indicates that the meter reset and establishes a new baseline. + +`FunctionTimer` doesn't expose individual durations, so the integration can't produce a distribution or percentiles for it. To calculate a weighted mean, divide the sum of `${convertedName}.total_time` by the sum of `${convertedName}.count`. + +## Configure Polling + +Passive polling uses one background worker per `SentryMeterRegistry`. Active metrics use the Sentry scope and trace context present when they're recorded, while passive metrics use the context available on the polling thread. + + + +Change the interval in milliseconds, or set it to `0` to disable passive polling: + +```properties {filename:application.properties} +sentry.micrometer.poll-interval-millis=0 +``` + + + + + +Pass the interval in milliseconds to the registry constructor. Set it to `0` to disable passive polling: + +```java +import io.sentry.micrometer.SentryMeterRegistry; + +SentryMeterRegistry sentryRegistry = new SentryMeterRegistry(30_000); +SentryMeterRegistry activeMetersOnly = new SentryMeterRegistry(0); +``` + + + +Disabling polling doesn't affect immediate forwarding for counters, timers, or distribution summaries. + +## Control Metric Volume + +Each counter increment, timer recording, and distribution summary recording creates one Sentry metric before the SDK batches metrics for transport. Apply a Micrometer `MeterFilter` to the Sentry registry to exclude noisy or high-cardinality meters without affecting other destinations. + + + +Use a typed `MeterRegistryCustomizer` so the filter applies only to `SentryMeterRegistry`: + +```java {tabTitle:Spring Boot 2 and 3}{filename:MetricsConfiguration.java}{mdExpandTabs} +import io.micrometer.core.instrument.config.MeterFilter; +import io.sentry.micrometer.SentryMeterRegistry; +import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class MetricsConfiguration { + @Bean + MeterRegistryCustomizer sentryMetricsFilter() { + return registry -> registry.config() + .meterFilter(MeterFilter.denyNameStartsWith("jvm.buffer")); + } +} +``` + +```java {tabTitle:Spring Boot 4}{filename:MetricsConfiguration.java} +import io.micrometer.core.instrument.config.MeterFilter; +import io.sentry.micrometer.SentryMeterRegistry; +import org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class MetricsConfiguration { + @Bean + MeterRegistryCustomizer sentryMetricsFilter() { + return registry -> registry.config() + .meterFilter(MeterFilter.denyNameStartsWith("jvm.buffer")); + } +} +``` + + + + + +Configure filters before registering meters: + +```java +import io.micrometer.core.instrument.config.MeterFilter; + +sentryRegistry.config() + .meterFilter(MeterFilter.denyNameStartsWith("jvm.buffer")); +``` + + + +Micrometer tags are forwarded to Sentry as metric attributes. Don't put sensitive or unbounded values in tags. For value- or attribute-based filtering, use Sentry's metrics `beforeSend` callback. + +Unsupported custom meter types remain available through Micrometer but aren't sent to Sentry. + +## Shut Down + + + +Spring Boot closes `SentryMeterRegistry` with the application context. No additional shutdown code is required. + + + + + +Remove and close the registry before closing Sentry. This stops passive polling and lets Sentry flush metrics it already accepted: + +```java +import io.micrometer.core.instrument.Metrics; +import io.sentry.Sentry; + +Metrics.removeRegistry(sentryRegistry); +sentryRegistry.close(); +Sentry.close(); +``` + + From 772d687e23fff25d94de4422bf0464ac0de7f0f4 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 17 Sep 2026 16:27:35 +0200 Subject: [PATCH 2/5] docs(java): Preserve dot-separated Micrometer names Document the Sentry registry's dot naming convention and update the verification example to use the exported metric name. Co-Authored-By: Claude --- docs/platforms/java/common/integrations/micrometer.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/java/common/integrations/micrometer.mdx b/docs/platforms/java/common/integrations/micrometer.mdx index e331a64819b7f..0d02ba15dace2 100644 --- a/docs/platforms/java/common/integrations/micrometer.mdx +++ b/docs/platforms/java/common/integrations/micrometer.mdx @@ -141,11 +141,11 @@ class CheckoutMetrics(private val registry: MeterRegistry) { } ``` -Call `recordCompletedOrder`, then open [Metrics in Sentry](/product/metrics/) and query for `checkout_completed`. The default naming convention converts dots in metric names to underscores. The `payment_method` tag is available as a metric attribute. +Call `recordCompletedOrder`, then open [Metrics in Sentry](/product/metrics/) and query for `checkout.completed`. The default naming convention preserves dot-separated metric names. The `payment_method` tag is available as a metric attribute. ## Metric Mappings -The registry applies its configured Micrometer `NamingConvention` to metric names, tag keys, and tag values. The default convention converts dots to underscores. +The registry applies its configured Micrometer `NamingConvention` to metric names, tag keys, and tag values. It defaults to `NamingConvention.dot`, which preserves names as written. You can configure another naming convention on `SentryMeterRegistry` without affecting other registries. The registry forwards active meters when your application records them: From 5ba80dfa1cfe6e275d16d199b9d6d3f94b97828d Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 18 Sep 2026 06:19:41 +0200 Subject: [PATCH 3/5] docs(java): Clarify Micrometer name preservation Document the identity naming convention, show that mixed separators remain unchanged, and describe mapped names as exported rather than converted. Co-Authored-By: Claude --- .../java/common/integrations/micrometer.mdx | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/platforms/java/common/integrations/micrometer.mdx b/docs/platforms/java/common/integrations/micrometer.mdx index 0d02ba15dace2..d98570d25596b 100644 --- a/docs/platforms/java/common/integrations/micrometer.mdx +++ b/docs/platforms/java/common/integrations/micrometer.mdx @@ -141,35 +141,35 @@ class CheckoutMetrics(private val registry: MeterRegistry) { } ``` -Call `recordCompletedOrder`, then open [Metrics in Sentry](/product/metrics/) and query for `checkout.completed`. The default naming convention preserves dot-separated metric names. The `payment_method` tag is available as a metric attribute. +Call `recordCompletedOrder`, then open [Metrics in Sentry](/product/metrics/) and query for `checkout.completed`. The default naming convention preserves metric names exactly as written. For example, `server.request_url` is exported as `server.request_url`. The `payment_method` tag is available as a metric attribute. ## Metric Mappings -The registry applies its configured Micrometer `NamingConvention` to metric names, tag keys, and tag values. It defaults to `NamingConvention.dot`, which preserves names as written. You can configure another naming convention on `SentryMeterRegistry` without affecting other registries. +The registry applies its configured Micrometer `NamingConvention` to metric names, tag keys, and tag values. It defaults to `NamingConvention.identity`, which doesn't replace or normalize any characters. You can configure another naming convention on `SentryMeterRegistry` without affecting other registries. The registry forwards active meters when your application records them: -| Micrometer Meter | Sentry Metric | Name | -| --------------------- | ---------------------------- | -------------- | -| `Counter` | Counter increment | Converted name | -| `Timer` | Distribution in milliseconds | Converted name | -| `DistributionSummary` | Distribution | Converted name | +| Micrometer Meter | Sentry Metric | Name | +| --------------------- | ---------------------------- | ------------- | +| `Counter` | Counter increment | Exported name | +| `Timer` | Distribution in milliseconds | Exported name | +| `DistributionSummary` | Distribution | Exported name | The registry polls meters that only expose their current or cumulative value every 60 seconds by default: -| Micrometer Meter | Sentry Metric | Name | -| ------------------------------- | -------------------------------------- | ----------------------------- | -| `Gauge` | Gauge | Converted name | -| `TimeGauge` | Gauge in milliseconds | Converted name | -| `LongTaskTimer` active tasks | Gauge | `${convertedName}.active` | -| `LongTaskTimer` active duration | Gauge in milliseconds | `${convertedName}.duration` | -| `FunctionCounter` | Positive counter delta | Converted name | -| `FunctionTimer` count | Positive counter delta | `${convertedName}.count` | -| `FunctionTimer` total time | Positive counter delta in milliseconds | `${convertedName}.total_time` | +| Micrometer Meter | Sentry Metric | Name | +| ------------------------------- | -------------------------------------- | ---------------------------- | +| `Gauge` | Gauge | Exported name | +| `TimeGauge` | Gauge in milliseconds | Exported name | +| `LongTaskTimer` active tasks | Gauge | `${exportedName}.active` | +| `LongTaskTimer` active duration | Gauge in milliseconds | `${exportedName}.duration` | +| `FunctionCounter` | Positive counter delta | Exported name | +| `FunctionTimer` count | Positive counter delta | `${exportedName}.count` | +| `FunctionTimer` total time | Positive counter delta in milliseconds | `${exportedName}.total_time` | The first successful poll of a function meter establishes its baseline and sends nothing. Later polls send positive changes. A lower value indicates that the meter reset and establishes a new baseline. -`FunctionTimer` doesn't expose individual durations, so the integration can't produce a distribution or percentiles for it. To calculate a weighted mean, divide the sum of `${convertedName}.total_time` by the sum of `${convertedName}.count`. +`FunctionTimer` doesn't expose individual durations, so the integration can't produce a distribution or percentiles for it. To calculate a weighted mean, divide the sum of `${exportedName}.total_time` by the sum of `${exportedName}.count`. ## Configure Polling From a8430121d9023021f1f43d745b4b6c3595648ea3 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 18 Sep 2026 15:01:04 +0200 Subject: [PATCH 4/5] docs(java): Clarify FunctionTimer delta alignment Document that FunctionTimer count and total-time values use independent baselines. Remove the unsafe weighted-mean recipe because failures and resets can make the exported deltas cover different polling windows. Co-Authored-By: Claude --- docs/platforms/java/common/integrations/micrometer.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/java/common/integrations/micrometer.mdx b/docs/platforms/java/common/integrations/micrometer.mdx index d98570d25596b..45805b7c7e283 100644 --- a/docs/platforms/java/common/integrations/micrometer.mdx +++ b/docs/platforms/java/common/integrations/micrometer.mdx @@ -167,9 +167,9 @@ The registry polls meters that only expose their current or cumulative value eve | `FunctionTimer` count | Positive counter delta | `${exportedName}.count` | | `FunctionTimer` total time | Positive counter delta in milliseconds | `${exportedName}.total_time` | -The first successful poll of a function meter establishes its baseline and sends nothing. Later polls send positive changes. A lower value indicates that the meter reset and establishes a new baseline. +The first successful finite poll establishes a function meter's baseline and sends nothing. For `FunctionTimer`, count and total time are polled and baselined independently. Later polls send positive deltas for each value. If a value decreases, the integration treats it as a reset and establishes a new baseline without sending a delta. -`FunctionTimer` doesn't expose individual durations, so the integration can't produce a distribution or percentiles for it. To calculate a weighted mean, divide the sum of `${exportedName}.total_time` by the sum of `${exportedName}.count`. +`FunctionTimer` doesn't expose individual durations, so the integration can't produce a distribution or percentiles. Count and total-time deltas can cover different polling windows after a failed or non-finite read or an independent reset, so they can't always be combined to calculate a reliable mean. ## Configure Polling From a8ca35af2b7eaef83547707e7544c419259252ed Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 18 Sep 2026 15:12:16 +0200 Subject: [PATCH 5/5] docs(java): Clarify Micrometer starter prerequisite State that Spring Boot users need the matching Sentry starter in addition to the Micrometer module so the documented auto-configuration is loaded. Co-Authored-By: Claude --- docs/platforms/java/common/integrations/micrometer.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/java/common/integrations/micrometer.mdx b/docs/platforms/java/common/integrations/micrometer.mdx index 45805b7c7e283..3318e9a379560 100644 --- a/docs/platforms/java/common/integrations/micrometer.mdx +++ b/docs/platforms/java/common/integrations/micrometer.mdx @@ -13,7 +13,7 @@ Add `sentry-micrometer` to the application that records your Micrometer metrics. -The Sentry Spring Boot starters don't include this module automatically. Spring Boot Actuator supplies Micrometer and its automatically registered HTTP server, JVM, process, and logging metrics. Add Actuator if your application doesn't already use it. +In addition to the matching Sentry Spring Boot starter for your Spring Boot version, add `sentry-micrometer`. Spring Boot Actuator supplies Micrometer and its automatically registered HTTP server, JVM, process, and logging metrics. Add Actuator if your application doesn't already use it. ```groovy {tabTitle:Gradle}{filename:build.gradle} implementation 'io.sentry:sentry-micrometer:{{@inject packages.version('sentry.java.micrometer', '8.58.0') }}'