From 8c8a736736107abceb0270402826076ea20e84c6 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 21 Nov 2025 17:07:52 +0100 Subject: [PATCH 01/11] add example for spring with declarative config --- .github/renovate.json5 | 9 +++ .github/workflows/oats-tests.yml | 1 + .mise/tasks/oats-tests.sh | 5 ++ README.md | 10 ++++ settings.gradle.kts | 1 + spring-declarative-configuration/README.md | 1 + .../build.gradle.kts | 29 +++++++++ .../oats/Dockerfile | 8 +++ .../oats/docker-compose.yml | 15 +++++ .../oats/oats.yaml | 26 ++++++++ .../examples/fileconfig/ApiController.java | 21 +++++++ .../examples/fileconfig/Application.java | 17 ++++++ .../src/main/resources/application.yaml | 59 +++++++++++++++++++ 13 files changed, 202 insertions(+) create mode 100644 spring-declarative-configuration/README.md create mode 100644 spring-declarative-configuration/build.gradle.kts create mode 100644 spring-declarative-configuration/oats/Dockerfile create mode 100644 spring-declarative-configuration/oats/docker-compose.yml create mode 100644 spring-declarative-configuration/oats/oats.yaml create mode 100644 spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/ApiController.java create mode 100644 spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/Application.java create mode 100644 spring-declarative-configuration/src/main/resources/application.yaml diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 1b2281e927..8a7124746c 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -40,6 +40,15 @@ "matchUpdateTypes": ["major"], "enabled": false }, + { + // Spring starter doesn't support Spring Boot 4 yet + "matchPackageNames": ["org.springframework.boot"], + "matchFilePatterns": [ + "spring-declarative-configuration/build.gradle.kts" + ], + "matchUpdateTypes": ["major"], + "enabled": false + }, { // Skip locally built dice image used in logging-k8s-stdout-otlp-json "matchManagers": ["kubernetes"], diff --git a/.github/workflows/oats-tests.yml b/.github/workflows/oats-tests.yml index d8d84edb96..598a16351a 100644 --- a/.github/workflows/oats-tests.yml +++ b/.github/workflows/oats-tests.yml @@ -10,6 +10,7 @@ on: - .mise/tasks/oats-tests.sh - 'logging-k8s-stdout-otlp-json/**' - 'javaagent-declarative-configuration/**' + - 'spring-declarative-configuration/**' - 'doc-snippets/extensions-minimal/**' workflow_dispatch: diff --git a/.mise/tasks/oats-tests.sh b/.mise/tasks/oats-tests.sh index 9b73e820d3..4e831fc7a1 100755 --- a/.mise/tasks/oats-tests.sh +++ b/.mise/tasks/oats-tests.sh @@ -11,5 +11,10 @@ pushd javaagent-declarative-configuration ../gradlew clean bootJar popd +pushd spring-declarative-configuration +../gradlew clean bootJar +popd + oats -timeout 5m logging-k8s-stdout-otlp-json/ oats -timeout 5m javaagent-declarative-configuration/oats/ +oats -timeout 5m spring-declarative-configuration/oats/ diff --git a/README.md b/README.md index 7a35020f0b..e44a7ed91c 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,16 @@ To build the all of examples, run: OpenTelemetry SDK to use a Zipkin exporter and send spans to a Zipkin backend using the OpenTelemetry API. - Note: This example requires Docker to be installed. +- [Declarative Configuration with the OpenTelemetry Java Agent](javaagent-declarative-configuration) + - This module demonstrates how to use declarative configuration with the + OpenTelemetry Java Agent to configure tracing behavior, including + excluding specific endpoints from tracing. + - Note: This example requires Java 17 or higher. +- [Declarative Configuration with the OpenTelemetry Spring Boot Starter](spring-declarative-configuration) + - This module demonstrates how to use declarative configuration with the + OpenTelemetry Spring Boot Starter to configure tracing behavior, + including excluding specific endpoints from tracing. + - Note: This example requires Java 17 or higher. ## Contributing diff --git a/settings.gradle.kts b/settings.gradle.kts index cd6cd2eca4..bd0126598b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -71,6 +71,7 @@ include( ":opentelemetry-examples-telemetry-testing", ":opentelemetry-examples-zipkin", ":opentelemetry-examples-spring-native", + ":opentelemetry-examples-spring-declarative-configuration", ":opentelemetry-examples-kotlin-extension", ":opentelemetry-examples-grpc", ":opentelemetry-examples-resource-detection-gcp", diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md new file mode 100644 index 0000000000..1333ed77b7 --- /dev/null +++ b/spring-declarative-configuration/README.md @@ -0,0 +1 @@ +TODO diff --git a/spring-declarative-configuration/build.gradle.kts b/spring-declarative-configuration/build.gradle.kts new file mode 100644 index 0000000000..7d3529034e --- /dev/null +++ b/spring-declarative-configuration/build.gradle.kts @@ -0,0 +1,29 @@ +import org.gradle.kotlin.dsl.named +import org.springframework.boot.gradle.plugin.SpringBootPlugin +import org.springframework.boot.gradle.tasks.bundling.BootJar + +plugins { + id("java") + id("org.springframework.boot") version "3.5.7" +} + +description = "OpenTelemetry Example for Spring Boot with Declarative Configuration" + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +dependencies { + implementation(platform(SpringBootPlugin.BOM_COORDINATES)) + implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.22.0")) + implementation("org.springframework.boot:spring-boot-starter-actuator") + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter") +} + +tasks.named("bootJar") { + archiveFileName = "spring-declarative-configuration.jar" +} + diff --git a/spring-declarative-configuration/oats/Dockerfile b/spring-declarative-configuration/oats/Dockerfile new file mode 100644 index 0000000000..aa69c95f7d --- /dev/null +++ b/spring-declarative-configuration/oats/Dockerfile @@ -0,0 +1,8 @@ +FROM eclipse-temurin:21.0.9_10-jre@sha256:4332b7939ba5b7fabde48f4da21ebe45a4f8943d5b3319720c321ac577e65fb1 + +WORKDIR /usr/src/app/ + +ADD ./build/libs/spring-declarative-configuration.jar ./app.jar + +EXPOSE 8080 +ENTRYPOINT [ "java", "-jar", "./app.jar" ] diff --git a/spring-declarative-configuration/oats/docker-compose.yml b/spring-declarative-configuration/oats/docker-compose.yml new file mode 100644 index 0000000000..d8fd00f6d2 --- /dev/null +++ b/spring-declarative-configuration/oats/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' +services: + app: + build: + context: ../ + dockerfile: oats/Dockerfile + environment: + SPRING_OTEL_EXPORTER_OTLP_ENDPOINT: http://lgtm:4318 + ports: + - "8080:8080" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] + interval: 10s + timeout: 5s + retries: 3 diff --git a/spring-declarative-configuration/oats/oats.yaml b/spring-declarative-configuration/oats/oats.yaml new file mode 100644 index 0000000000..3be11e39ed --- /dev/null +++ b/spring-declarative-configuration/oats/oats.yaml @@ -0,0 +1,26 @@ +# OATS is an acceptance testing framework for OpenTelemetry - https://github.com/grafana/oats + +docker-compose: + files: + - ./docker-compose.yml + app-service: app + app-docker-tag: javaagent-declarative-config:latest + app-docker-port: 8080 + +input: + # This endpoint should be traced normally + - path: /api/example + # This endpoint should NOT be traced (excluded by declarative config) + # We send the request but don't assert spans for it - the absence of spans + # for /actuator/health demonstrates the sampling rule is working + - path: /actuator/health + +expected: + traces: + # Verify that /api/example creates a trace with SERVER span + - traceql: '{ span.http.route = "/api/example" }' + spans: + - name: "GET /api/example" + attributes: + http.request.method: "GET" + http.route: "/api/example" \ No newline at end of file diff --git a/spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/ApiController.java b/spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/ApiController.java new file mode 100644 index 0000000000..e9c3d43c15 --- /dev/null +++ b/spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/ApiController.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.examples.fileconfig; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api") +public class ApiController { + + @GetMapping("/example") + public ResponseEntity example() { + return ResponseEntity.ok("Hello from OpenTelemetry example API!"); + } +} diff --git a/spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/Application.java b/spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/Application.java new file mode 100644 index 0000000000..7987bb5c71 --- /dev/null +++ b/spring-declarative-configuration/src/main/java/io/opentelemetry/examples/fileconfig/Application.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.examples.fileconfig; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-declarative-configuration/src/main/resources/application.yaml b/spring-declarative-configuration/src/main/resources/application.yaml new file mode 100644 index 0000000000..d18c66ee08 --- /dev/null +++ b/spring-declarative-configuration/src/main/resources/application.yaml @@ -0,0 +1,59 @@ +otel: + # IMPORTANT: + # 1. The auto-suggested properties are not correct, because they are based on the non-declarative config schema. + # 2. Use https://github.com/open-telemetry/opentelemetry-configuration for details on schema and examples, but + # indent all examples by two spaces to fit under the "otel:" root node (for Spring Boot declarative config). + + file_format: "1.0-rc.2" + + resource: + attributes: + - name: service.name + value: spring-boot-declarative-config-example + + propagator: + composite: + - tracecontext: + - baggage: + + tracer_provider: + processors: + - batch: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces + + # Configure a console exporter for exploring without a collector/backend + - batch: + exporter: + console: + + # Configure sampling to exclude health check endpoints + sampler: + rule_based_routing: + fallback_sampler: + always_on: + # Filter to spans of this span_kind. Must be one of: SERVER, CLIENT, INTERNAL, CONSUMER, PRODUCER. + span_kind: SERVER # only apply to server spans + # List of rules describing spans to drop. Spans are dropped if they match one of the rules. + rules: + # The action to take when the rule is matches. Must be of: DROP, RECORD_AND_SAMPLE. + - action: DROP + # The span attribute to match against. + attribute: url.path + # The pattern to compare the span attribute to. + pattern: /actuator.* + + meter_provider: + readers: + - periodic: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/metrics + + logger_provider: + processors: + - batch: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/logs From d983c9c9a2be2497034def570e2c72c7152cb365 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 21 Nov 2025 19:23:14 +0100 Subject: [PATCH 02/11] add example for spring with declarative config --- spring-declarative-configuration/oats/docker-compose.yml | 4 +++- .../src/main/resources/application.yaml | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/spring-declarative-configuration/oats/docker-compose.yml b/spring-declarative-configuration/oats/docker-compose.yml index d8fd00f6d2..e6a0c2580e 100644 --- a/spring-declarative-configuration/oats/docker-compose.yml +++ b/spring-declarative-configuration/oats/docker-compose.yml @@ -5,7 +5,9 @@ services: context: ../ dockerfile: oats/Dockerfile environment: - SPRING_OTEL_EXPORTER_OTLP_ENDPOINT: http://lgtm:4318 + OTEL_TRACER_PROVIDER_PROCESSORS_0_BATCH_EXPORTER_OTLP_HTTP_ENDPOINT: http://lgtm:4318/v1/traces + OTEL_METER_PROVIDER_READERS_0_PERIODIC_EXPORTER_OTLP_HTTP_ENDPOINT: http://lgtm:4318/v1/metrics + OTEL_LOGGER_PROVIDER_PROCESSORS_0_BATCH_EXPORTER_OTLP_HTTP_ENDPOINT: http://lgtm:4318/v1/logs ports: - "8080:8080" healthcheck: diff --git a/spring-declarative-configuration/src/main/resources/application.yaml b/spring-declarative-configuration/src/main/resources/application.yaml index d18c66ee08..37a7b546c7 100644 --- a/spring-declarative-configuration/src/main/resources/application.yaml +++ b/spring-declarative-configuration/src/main/resources/application.yaml @@ -21,7 +21,7 @@ otel: - batch: exporter: otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces + endpoint: http://localhost:4318/v1/traces # Configure a console exporter for exploring without a collector/backend - batch: @@ -49,11 +49,11 @@ otel: - periodic: exporter: otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/metrics + endpoint: http://localhost:4318/v1/metrics logger_provider: processors: - batch: exporter: otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/logs + endpoint: http://localhost:4318/v1/logs From 299156b1761f78d2c8cf81c88cc6f1611f86e34a Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Sun, 23 Nov 2025 16:26:34 +0100 Subject: [PATCH 03/11] use spring style env var syntax --- spring-declarative-configuration/oats/docker-compose.yml | 4 +--- .../src/main/resources/application.yaml | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/spring-declarative-configuration/oats/docker-compose.yml b/spring-declarative-configuration/oats/docker-compose.yml index e6a0c2580e..2191ba601f 100644 --- a/spring-declarative-configuration/oats/docker-compose.yml +++ b/spring-declarative-configuration/oats/docker-compose.yml @@ -5,9 +5,7 @@ services: context: ../ dockerfile: oats/Dockerfile environment: - OTEL_TRACER_PROVIDER_PROCESSORS_0_BATCH_EXPORTER_OTLP_HTTP_ENDPOINT: http://lgtm:4318/v1/traces - OTEL_METER_PROVIDER_READERS_0_PERIODIC_EXPORTER_OTLP_HTTP_ENDPOINT: http://lgtm:4318/v1/metrics - OTEL_LOGGER_PROVIDER_PROCESSORS_0_BATCH_EXPORTER_OTLP_HTTP_ENDPOINT: http://lgtm:4318/v1/logs + OTEL_EXPORTER_OTLP_ENDPOINT: http://lgtm:4318 ports: - "8080:8080" healthcheck: diff --git a/spring-declarative-configuration/src/main/resources/application.yaml b/spring-declarative-configuration/src/main/resources/application.yaml index 37a7b546c7..d18c66ee08 100644 --- a/spring-declarative-configuration/src/main/resources/application.yaml +++ b/spring-declarative-configuration/src/main/resources/application.yaml @@ -21,7 +21,7 @@ otel: - batch: exporter: otlp_http: - endpoint: http://localhost:4318/v1/traces + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces # Configure a console exporter for exploring without a collector/backend - batch: @@ -49,11 +49,11 @@ otel: - periodic: exporter: otlp_http: - endpoint: http://localhost:4318/v1/metrics + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/metrics logger_provider: processors: - batch: exporter: otlp_http: - endpoint: http://localhost:4318/v1/logs + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/logs From b11df227ccc99e2daa7468da6e6e5ea6c36d0281 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 24 Nov 2025 08:26:43 +0100 Subject: [PATCH 04/11] comment --- .../src/main/resources/application.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-declarative-configuration/src/main/resources/application.yaml b/spring-declarative-configuration/src/main/resources/application.yaml index d18c66ee08..29d4f6393c 100644 --- a/spring-declarative-configuration/src/main/resources/application.yaml +++ b/spring-declarative-configuration/src/main/resources/application.yaml @@ -21,6 +21,7 @@ otel: - batch: exporter: otlp_http: + # Note: Spring uses : instead of :- as separator for the default value endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces # Configure a console exporter for exploring without a collector/backend @@ -49,6 +50,7 @@ otel: - periodic: exporter: otlp_http: + # Note: Spring uses : instead of :- as separator for the default value endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/metrics logger_provider: @@ -56,4 +58,5 @@ otel: - batch: exporter: otlp_http: + # Note: Spring uses : instead of :- as separator for the default value endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/logs From 1c442c2198f00c1f7724266b8bb55522ef9aebfb Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 24 Nov 2025 09:30:51 +0100 Subject: [PATCH 05/11] add doc instructions --- spring-declarative-configuration/README.md | 14 +++++++++++++- .../src/main/resources/application.yaml | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md index 1333ed77b7..7945a2a4aa 100644 --- a/spring-declarative-configuration/README.md +++ b/spring-declarative-configuration/README.md @@ -1 +1,13 @@ -TODO +Instructions for Copilot: +- Take ../javaagent-declarative-configuration as a basis: replace this file with the readme content and adjust as needed. +- Focus on documenting the usage of declarative configuration with Spring Boot applications. +- Adjust the example to use the OpenTelemetry Spring Boot Starter instead of the Java Agent. +- Make sure to highlight any differences or important notes specific to the Spring Boot Starter usage of declarative configuration. +- requires 2.22.0+ version of the spring starter +- The auto-suggested properties in IDNs are not correct, because they are based on the non-declarative config schema. +- Use https://github.com/open-telemetry/opentelemetry-configuration for details on schema and examples, but + indent all examples by two spaces to fit under the "otel:" root node (for Spring Boot declarative config). +- "file_format" serves as opt-in to declarative config +- Spring uses : instead of :- as separator for the default value, e.g. ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces instead of ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/traces +- add a link to the application.yaml configuration file in this module +- `configureSampler` in `OpenTelemetryConfig` in the `spring-native` module can serve as an example of programmatic configuration that mimics declarative config behavior to filter out health checks diff --git a/spring-declarative-configuration/src/main/resources/application.yaml b/spring-declarative-configuration/src/main/resources/application.yaml index 29d4f6393c..c94b08843a 100644 --- a/spring-declarative-configuration/src/main/resources/application.yaml +++ b/spring-declarative-configuration/src/main/resources/application.yaml @@ -4,7 +4,7 @@ otel: # 2. Use https://github.com/open-telemetry/opentelemetry-configuration for details on schema and examples, but # indent all examples by two spaces to fit under the "otel:" root node (for Spring Boot declarative config). - file_format: "1.0-rc.2" + file_format: "1.0-rc.2" # "file_format" serves as opt-in to declarative config resource: attributes: From b2c175e34ec32ff2e91e358851e9ee53133eae65 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 24 Nov 2025 09:36:44 +0100 Subject: [PATCH 06/11] copilot --- spring-declarative-configuration/README.md | 114 ++++++++++++++++++--- 1 file changed, 101 insertions(+), 13 deletions(-) diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md index 7945a2a4aa..2efc3ddac9 100644 --- a/spring-declarative-configuration/README.md +++ b/spring-declarative-configuration/README.md @@ -1,13 +1,101 @@ -Instructions for Copilot: -- Take ../javaagent-declarative-configuration as a basis: replace this file with the readme content and adjust as needed. -- Focus on documenting the usage of declarative configuration with Spring Boot applications. -- Adjust the example to use the OpenTelemetry Spring Boot Starter instead of the Java Agent. -- Make sure to highlight any differences or important notes specific to the Spring Boot Starter usage of declarative configuration. -- requires 2.22.0+ version of the spring starter -- The auto-suggested properties in IDNs are not correct, because they are based on the non-declarative config schema. -- Use https://github.com/open-telemetry/opentelemetry-configuration for details on schema and examples, but - indent all examples by two spaces to fit under the "otel:" root node (for Spring Boot declarative config). -- "file_format" serves as opt-in to declarative config -- Spring uses : instead of :- as separator for the default value, e.g. ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces instead of ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/traces -- add a link to the application.yaml configuration file in this module -- `configureSampler` in `OpenTelemetryConfig` in the `spring-native` module can serve as an example of programmatic configuration that mimics declarative config behavior to filter out health checks +# Spring Boot Declarative Configuration Example + +This example demonstrates how to use [declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) with the OpenTelemetry Spring Boot Starter (requires version 2.22.0+). Declarative configuration allows you to control tracing and metrics behavior using a YAML file, without code changes. + +The configuration file is located at [`application.yaml`](./application.yaml). + +This Spring Boot application includes two endpoints: +- `/actuator/health` - A health check endpoint (from Spring Boot Actuator) that is configured to be excluded from tracing +- `/api/example` - A simple API endpoint that will be traced normally + +## End-to-End Instructions + +### Prerequisites +* Java 17 or higher +* OpenTelemetry Spring Boot Starter version 2.22.0 or newer + +Add the starter to your `build.gradle`: +```kotlin +dependencies { + implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter:2.22.0") +} +``` + +### Step 1: Build the Application + +```bash +# Build the JAR - Run from the spring-declarative-configuration directory +../gradlew bootJar +``` + +### Step 2: Run the Application + +```bash +# From the spring-declarative-configuration directory +java -jar build/libs/spring-declarative-configuration.jar +``` + +### Step 3: Test the Endpoints + +Open a new terminal and test both endpoints: + +```bash +# This endpoint will NOT be traced (excluded by configuration) +curl http://localhost:8080/actuator/health + +# This endpoint WILL be traced normally +curl http://localhost:8080/api/example +``` + +### Step 4: Verify Tracing Behavior + +Check your tracing backend or logs to see: +- Health check requests (`/actuator/health`) should NOT generate traces (excluded by configuration) +- API requests (`/api/example`) should generate traces + +## Declarative Configuration + +Declarative configuration is enabled by setting the `file_format` property in your `application.yaml` under the `otel:` root node. All configuration must be indented under `otel:` for Spring Boot. + +See [OpenTelemetry Configuration Schema and Examples](https://github.com/open-telemetry/opentelemetry-configuration) for details. + +Example configuration to exclude health checks from tracing: + +```yaml +otel: + file_format: declarative + tracer_provider: + sampler: + rule_based_routing: + fallback_sampler: + always_on: + span_kind: SERVER + rules: + - action: DROP + attribute: url.path + pattern: /actuator.* +``` + +**Important Notes:** +- Spring Boot uses `:` as the separator for default values in property expressions, e.g. `${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces` (not `:-`). +- The auto-suggested properties in IDEs may be incorrect, as they are based on the non-declarative config schema. +- The `file_format` property is required to opt-in to declarative configuration. +- Refer to the [`application.yaml`](./application.yaml) configuration file in this module for the complete list of available properties and their descriptions. + +## Programmatic Configuration Example + +If you need to filter out health checks programmatically (instead of declarative config), see [`OpenTelemetryConfig.java`](../spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java) in the `spring-native` module. The `configureSampler` method demonstrates how to drop actuator endpoints from tracing using the RuleBasedRoutingSampler: + +```java +// ...existing code... +private RuleBasedRoutingSampler configureSampler(Sampler fallback, ConfigProperties config) { + return RuleBasedRoutingSampler.builder(SpanKind.SERVER, fallback) + .drop(UrlAttributes.URL_PATH, "^/actuator") + .build(); +} +// ...existing code... +``` + +## Further Reading +- [OpenTelemetry Declarative Configuration Schema](https://github.com/open-telemetry/opentelemetry-configuration) +- [Spring Boot Starter Documentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/spring/spring-boot-autoconfigure) From d90aa1cc98f1f9e9550d00849259f1868ef6327d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 24 Nov 2025 09:48:45 +0100 Subject: [PATCH 07/11] gpt 5.1 --- spring-declarative-configuration/README.md | 265 +++++++++++++++++---- 1 file changed, 220 insertions(+), 45 deletions(-) diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md index 2efc3ddac9..4da0a42a19 100644 --- a/spring-declarative-configuration/README.md +++ b/spring-declarative-configuration/README.md @@ -1,70 +1,155 @@ # Spring Boot Declarative Configuration Example -This example demonstrates how to use [declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) with the OpenTelemetry Spring Boot Starter (requires version 2.22.0+). Declarative configuration allows you to control tracing and metrics behavior using a YAML file, without code changes. +This example demonstrates how to use [declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) +with the OpenTelemetry Spring Boot Starter to configure tracing, metrics, and logging for a Spring Boot application. -The configuration file is located at [`application.yaml`](./application.yaml). +Instead of using the OpenTelemetry Java Agent and an `otel-agent-config.yaml` file, this module uses the +[OpenTelemetry Spring Boot Starter](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/spring/spring-boot-autoconfigure) +and configures declarative behavior via standard Spring Boot configuration in `application.yaml`. + +> **Requirement:** Declarative configuration via the Spring Boot Starter requires version **2.22.0 or newer** of the +> OpenTelemetry Spring Boot Starter. + +The main configuration file for this example is: + +- [`src/main/resources/application.yaml`](./src/main/resources/application.yaml) + +For the underlying declarative configuration schema and additional examples, see the +[opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) repository. +Remember that when you copy examples from that repository into a Spring Boot app, you must nest them under the +`otel:` root node (two-space indentation for all keys shown below). This Spring Boot application includes two endpoints: -- `/actuator/health` - A health check endpoint (from Spring Boot Actuator) that is configured to be excluded from tracing -- `/api/example` - A simple API endpoint that will be traced normally + +- `/actuator/health` – A health check endpoint (from Spring Boot Actuator) that is configured to be **excluded** from tracing +- `/api/example` – A simple API endpoint that **will be traced** normally ## End-to-End Instructions ### Prerequisites -* Java 17 or higher -* OpenTelemetry Spring Boot Starter version 2.22.0 or newer - -Add the starter to your `build.gradle`: -```kotlin -dependencies { - implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter:2.22.0") -} -``` + +- Java 17 or higher +- OpenTelemetry Spring Boot Starter **2.22.0+** on the classpath of this application (already configured in this + example’s build files) ### Step 1: Build the Application +From the `spring-declarative-configuration` directory: + ```bash -# Build the JAR - Run from the spring-declarative-configuration directory ../gradlew bootJar ``` -### Step 2: Run the Application +This builds the Spring Boot fat JAR for the example application. + +### Step 2: Run the Spring Boot Application + +Run the application as a normal Spring Boot JAR – no `-javaagent` flag and no separate `otel-agent-config.yaml` file +are needed. Declarative configuration is picked up from `application.yaml` by the Spring Boot Starter. ```bash -# From the spring-declarative-configuration directory java -jar build/libs/spring-declarative-configuration.jar ``` +The Spring Boot Starter will automatically: + +- Initialize OpenTelemetry SDK +- Read declarative configuration under the `otel:` root in `application.yaml` +- Apply exporters, processors, and sampler rules defined there + ### Step 3: Test the Endpoints -Open a new terminal and test both endpoints: +In a separate terminal, call both endpoints: ```bash -# This endpoint will NOT be traced (excluded by configuration) +# This endpoint will NOT be traced (excluded by declarative configuration) curl http://localhost:8080/actuator/health # This endpoint WILL be traced normally curl http://localhost:8080/api/example ``` -### Step 4: Verify Tracing Behavior +### Step 4: Verify Tracing, Metrics, and Logs + +By default, this example configures: -Check your tracing backend or logs to see: -- Health check requests (`/actuator/health`) should NOT generate traces (excluded by configuration) -- API requests (`/api/example`) should generate traces +- An OTLP HTTP exporter for traces, metrics, and logs +- A console exporter for traces for easy local inspection -## Declarative Configuration +Check the application logs to see that: -Declarative configuration is enabled by setting the `file_format` property in your `application.yaml` under the `otel:` root node. All configuration must be indented under `otel:` for Spring Boot. +- Health check requests (`/actuator/health`) **do not** generate spans (dropped by sampler rules) +- Requests to `/api/example` **do** generate spans and are exported to console and/or OTLP -See [OpenTelemetry Configuration Schema and Examples](https://github.com/open-telemetry/opentelemetry-configuration) for details. +If you have an OTLP-compatible backend (e.g., the OpenTelemetry Collector, Jaeger, Tempo, etc.) listening on +`http://localhost:4318`, you can inspect the exported telemetry there as well. -Example configuration to exclude health checks from tracing: +## Declarative Configuration with Spring Boot + +The declarative configuration used by this example lives in [`application.yaml`](./src/main/resources/application.yaml) +under the `otel:` root key. ```yaml otel: - file_format: declarative + # ... see src/main/resources/application.yaml for the full configuration +``` + +This layout follows the declarative configuration schema defined in the +[opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) repository, but adapted +for Spring Boot: + +- All OpenTelemetry configuration keys live under the `otel:` root +- Configuration blocks from the reference repo (such as `tracer_provider`, `meter_provider`, `logger_provider`, etc.) + are indented by **two spaces** beneath `otel:` +- The configuration is loaded via the OpenTelemetry Spring Boot Starter instead of the Java Agent + +### Opting In with `file_format` + +Declarative configuration is **opt-in**. In this Spring Boot example, you enable declarative configuration by setting +`file_format` under `otel:` in `application.yaml`: + +```yaml +otel: + file_format: "1.0-rc.2" + # ... other configuration +``` + +The `file_format` value follows the versions defined in the +[declarative configuration specification](https://github.com/open-telemetry/opentelemetry-configuration). +If `file_format` is missing, declarative configuration is not applied. + +### Example: Exporters and Sampler Rules (Spring Style) + +Below is a simplified view of the configuration used in this module. All keys are indented under `otel:` as required by +Spring Boot declarative configuration. Refer to the actual +[`application.yaml`](./src/main/resources/application.yaml) for the complete version. + +```yaml +otel: + file_format: "1.0-rc.2" + + resource: + attributes: + - name: service.name + value: spring-boot-declarative-config-example + + propagator: + composite: + - tracecontext: + - baggage: + tracer_provider: + processors: + - batch: + exporter: + otlp_http: + # Note: Spring uses : instead of :- as separator for the default value + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces + + - batch: + exporter: + console: + sampler: rule_based_routing: fallback_sampler: @@ -74,28 +159,118 @@ otel: - action: DROP attribute: url.path pattern: /actuator.* + + meter_provider: + readers: + - periodic: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/metrics + + logger_provider: + processors: + - batch: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/logs ``` -**Important Notes:** -- Spring Boot uses `:` as the separator for default values in property expressions, e.g. `${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces` (not `:-`). -- The auto-suggested properties in IDEs may be incorrect, as they are based on the non-declarative config schema. -- The `file_format` property is required to opt-in to declarative configuration. -- Refer to the [`application.yaml`](./application.yaml) configuration file in this module for the complete list of available properties and their descriptions. +This configuration is conceptually equivalent to the Java Agent example’s `rule_based_routing` sampler (from +`javaagent-declarative-configuration/otel-agent-config.yaml`): + +- It uses the `rule_based_routing` sampler contribution +- It restricts evaluation to `SERVER` spans +- It drops (`DROP`) spans whose `url.path` matches `/actuator.*` (e.g., `/actuator/health`) +- All other server requests are sampled by the `always_on` fallback sampler + +## Spring Boot Starter–Specific Notes + +### Spring Boot Starter Version + +- Declarative configuration is supported by the OpenTelemetry Spring Boot Starter starting with version **2.22.0** +- Ensure your dependencies use at least this version; otherwise, `file_format` and other declarative config features + may be ignored + +### Property Metadata and IDE Auto-Completion -## Programmatic Configuration Example +Most IDEs derive auto-completion for Spring properties from Spring Boot configuration metadata. At the time of this +example, that metadata is primarily based on the **non-declarative** configuration schema. -If you need to filter out health checks programmatically (instead of declarative config), see [`OpenTelemetryConfig.java`](../spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java) in the `spring-native` module. The `configureSampler` method demonstrates how to drop actuator endpoints from tracing using the RuleBasedRoutingSampler: +As a result: -```java -// ...existing code... -private RuleBasedRoutingSampler configureSampler(Sampler fallback, ConfigProperties config) { - return RuleBasedRoutingSampler.builder(SpanKind.SERVER, fallback) - .drop(UrlAttributes.URL_PATH, "^/actuator") - .build(); -} -// ...existing code... +- Auto-suggested properties in IDEs may be incomplete or incorrect for declarative configuration under `otel:` +- Some declarative configuration keys may not appear in auto-completion at all + +When in doubt: + +- Prefer the official schema and examples in + [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) +- Then adapt those examples by nesting them under the `otel:` root in your `application.yaml` + +### Placeholder Default Values: `:` vs `:-` + +Spring Boot’s property placeholder syntax differs slightly from generic examples you might see in OpenTelemetry docs. + +- Generic examples sometimes use `${VAR_NAME:-default}` for default values +- **Spring Boot uses `:` instead of `:-`** + +For example, in this module we configure the OTLP HTTP trace endpoint as: + +```yaml +otel: + tracer_provider: + processors: + - batch: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces ``` -## Further Reading -- [OpenTelemetry Declarative Configuration Schema](https://github.com/open-telemetry/opentelemetry-configuration) -- [Spring Boot Starter Documentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/spring/spring-boot-autoconfigure) +Here, `http://localhost:4318` is used as the default if `OTEL_EXPORTER_OTLP_ENDPOINT` is not set. + +When copying configuration from non-Spring examples, always convert `:-` to `:` in placeholders. + +## Declarative vs Programmatic Configuration + +Declarative configuration, as used in this example, allows you to express routing and sampling rules entirely in +configuration files. This is ideal for: + +- Operational teams that need to adjust sampling or filtering without changing code +- Environments where configuration is managed externally (Kubernetes ConfigMaps, Spring Cloud Config, etc.) + +For more advanced or dynamic scenarios, you can still use **programmatic** configuration. The `spring-native` module in +this repository contains an example of this: + +- See `configureSampler` in + [`OpenTelemetryConfig`](../spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java) +- It uses `RuleBasedRoutingSampler` programmatically to drop spans for actuator endpoints (`/actuator*`), replicating + the behavior we achieve declaratively via YAML in this module + +In many cases, you can start with declarative configuration (as in this module) and only fall back to programmatic +customization for highly dynamic or application-specific logic. + +## Troubleshooting and Tips + +If the behavior is not what you expect, here are a few things to check: + +- **Health checks are still traced** + - Verify the `rules` section under `otel.tracer_provider.sampler.rule_based_routing` in `application.yaml` + - Ensure the `pattern` matches your actual actuator paths (e.g., `/actuator.*`) + - Confirm that `span_kind` is set to `SERVER` (or another correct span kind for your traffic) + +- **No spans are exported** + - Confirm that `otel.file_format` is set correctly (for example, `"1.0-rc.2"`) + - Check that at least one exporter is configured (e.g., `otlp_http` or `console`) + - Look for startup warnings or errors related to OpenTelemetry configuration + +- **Properties seem to be ignored** + - Make sure you are modifying the correct `application.yaml` for the active Spring profile + - Verify that all configuration keys are indented correctly under the `otel:` root + - Double-check that any placeholders use `:` for defaults (e.g., `${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}`) + +If issues persist, compare your configuration to: + +- This module’s [`application.yaml`](./src/main/resources/application.yaml) +- The Java Agent example in [`javaagent-declarative-configuration`](../javaagent-declarative-configuration) +- The reference schemas and examples in + [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) From dec3d9d0aaeb41440d270dd3e9036cbee4af5dd8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 24 Nov 2025 09:55:38 +0100 Subject: [PATCH 08/11] formatting --- spring-declarative-configuration/README.md | 108 +++++++++++++-------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md index 4da0a42a19..84cfdf7283 100644 --- a/spring-declarative-configuration/README.md +++ b/spring-declarative-configuration/README.md @@ -1,13 +1,16 @@ # Spring Boot Declarative Configuration Example -This example demonstrates how to use [declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) -with the OpenTelemetry Spring Boot Starter to configure tracing, metrics, and logging for a Spring Boot application. +This example demonstrates how to +use [declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) +with the OpenTelemetry Spring Boot Starter to configure tracing, metrics, and logging for a Spring +Boot application. -Instead of using the OpenTelemetry Java Agent and an `otel-agent-config.yaml` file, this module uses the +Instead of using the OpenTelemetry Java Agent, this module uses the [OpenTelemetry Spring Boot Starter](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/spring/spring-boot-autoconfigure) and configures declarative behavior via standard Spring Boot configuration in `application.yaml`. -> **Requirement:** Declarative configuration via the Spring Boot Starter requires version **2.22.0 or newer** of the +> **Requirement:** Declarative configuration via the Spring Boot Starter requires version **2.22.0 +or newer** of the > OpenTelemetry Spring Boot Starter. The main configuration file for this example is: @@ -15,13 +18,16 @@ The main configuration file for this example is: - [`src/main/resources/application.yaml`](./src/main/resources/application.yaml) For the underlying declarative configuration schema and additional examples, see the -[opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) repository. -Remember that when you copy examples from that repository into a Spring Boot app, you must nest them under the +[opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) +repository. +Remember that when you copy examples from that repository into a Spring Boot app, you must nest them +under the `otel:` root node (two-space indentation for all keys shown below). This Spring Boot application includes two endpoints: -- `/actuator/health` – A health check endpoint (from Spring Boot Actuator) that is configured to be **excluded** from tracing +- `/actuator/health` – A health check endpoint (from Spring Boot Actuator) that is configured to be + **excluded** from tracing - `/api/example` – A simple API endpoint that **will be traced** normally ## End-to-End Instructions @@ -29,7 +35,8 @@ This Spring Boot application includes two endpoints: ### Prerequisites - Java 17 or higher -- OpenTelemetry Spring Boot Starter **2.22.0+** on the classpath of this application (already configured in this +- OpenTelemetry Spring Boot Starter **2.22.0+** on the classpath of this application (already + configured in this example’s build files) ### Step 1: Build the Application @@ -44,8 +51,10 @@ This builds the Spring Boot fat JAR for the example application. ### Step 2: Run the Spring Boot Application -Run the application as a normal Spring Boot JAR – no `-javaagent` flag and no separate `otel-agent-config.yaml` file -are needed. Declarative configuration is picked up from `application.yaml` by the Spring Boot Starter. +Run the application as a normal Spring Boot JAR – no `-javaagent` flag and no separate +`otel-agent-config.yaml` file +are needed. Declarative configuration is picked up from `application.yaml` by the Spring Boot +Starter. ```bash java -jar build/libs/spring-declarative-configuration.jar @@ -81,31 +90,36 @@ Check the application logs to see that: - Health check requests (`/actuator/health`) **do not** generate spans (dropped by sampler rules) - Requests to `/api/example` **do** generate spans and are exported to console and/or OTLP -If you have an OTLP-compatible backend (e.g., the OpenTelemetry Collector, Jaeger, Tempo, etc.) listening on +If you have an OTLP-compatible backend (e.g., the OpenTelemetry Collector, Jaeger, Tempo, etc.) +listening on `http://localhost:4318`, you can inspect the exported telemetry there as well. ## Declarative Configuration with Spring Boot -The declarative configuration used by this example lives in [`application.yaml`](./src/main/resources/application.yaml) +The declarative configuration used by this example lives in [ +`application.yaml`](./src/main/resources/application.yaml) under the `otel:` root key. ```yaml otel: - # ... see src/main/resources/application.yaml for the full configuration +# ... see src/main/resources/application.yaml for the full configuration ``` This layout follows the declarative configuration schema defined in the -[opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) repository, but adapted +[opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) +repository, but adapted for Spring Boot: - All OpenTelemetry configuration keys live under the `otel:` root -- Configuration blocks from the reference repo (such as `tracer_provider`, `meter_provider`, `logger_provider`, etc.) +- Configuration blocks from the reference repo (such as `tracer_provider`, `meter_provider`, + `logger_provider`, etc.) are indented by **two spaces** beneath `otel:` - The configuration is loaded via the OpenTelemetry Spring Boot Starter instead of the Java Agent ### Opting In with `file_format` -Declarative configuration is **opt-in**. In this Spring Boot example, you enable declarative configuration by setting +Declarative configuration is **opt-in**. In this Spring Boot example, you enable declarative +configuration by setting `file_format` under `otel:` in `application.yaml`: ```yaml @@ -120,7 +134,8 @@ If `file_format` is missing, declarative configuration is not applied. ### Example: Exporters and Sampler Rules (Spring Style) -Below is a simplified view of the configuration used in this module. All keys are indented under `otel:` as required by +Below is a simplified view of the configuration used in this module. All keys are indented under +`otel:` as required by Spring Boot declarative configuration. Refer to the actual [`application.yaml`](./src/main/resources/application.yaml) for the complete version. @@ -175,7 +190,8 @@ otel: endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/logs ``` -This configuration is conceptually equivalent to the Java Agent example’s `rule_based_routing` sampler (from +This configuration is conceptually equivalent to the Java Agent example’s `rule_based_routing` +sampler (from `javaagent-declarative-configuration/otel-agent-config.yaml`): - It uses the `rule_based_routing` sampler contribution @@ -187,18 +203,22 @@ This configuration is conceptually equivalent to the Java Agent example’s `rul ### Spring Boot Starter Version -- Declarative configuration is supported by the OpenTelemetry Spring Boot Starter starting with version **2.22.0** -- Ensure your dependencies use at least this version; otherwise, `file_format` and other declarative config features +- Declarative configuration is supported by the OpenTelemetry Spring Boot Starter starting with + version **2.22.0** +- Ensure your dependencies use at least this version; otherwise, `file_format` and other declarative + config features may be ignored ### Property Metadata and IDE Auto-Completion -Most IDEs derive auto-completion for Spring properties from Spring Boot configuration metadata. At the time of this +Most IDEs derive auto-completion for Spring properties from Spring Boot configuration metadata. At +the time of this example, that metadata is primarily based on the **non-declarative** configuration schema. As a result: -- Auto-suggested properties in IDEs may be incomplete or incorrect for declarative configuration under `otel:` +- Auto-suggested properties in IDEs may be incomplete or incorrect for declarative configuration + under `otel:` - Some declarative configuration keys may not appear in auto-completion at all When in doubt: @@ -209,7 +229,8 @@ When in doubt: ### Placeholder Default Values: `:` vs `:-` -Spring Boot’s property placeholder syntax differs slightly from generic examples you might see in OpenTelemetry docs. +Spring Boot’s property placeholder syntax differs slightly from generic examples you might see in +OpenTelemetry docs. - Generic examples sometimes use `${VAR_NAME:-default}` for default values - **Spring Boot uses `:` instead of `:-`** @@ -232,21 +253,27 @@ When copying configuration from non-Spring examples, always convert `:-` to `:` ## Declarative vs Programmatic Configuration -Declarative configuration, as used in this example, allows you to express routing and sampling rules entirely in +Declarative configuration, as used in this example, allows you to express routing and sampling rules +entirely in configuration files. This is ideal for: - Operational teams that need to adjust sampling or filtering without changing code -- Environments where configuration is managed externally (Kubernetes ConfigMaps, Spring Cloud Config, etc.) +- Environments where configuration is managed externally (Kubernetes ConfigMaps, Spring Cloud + Config, etc.) -For more advanced or dynamic scenarios, you can still use **programmatic** configuration. The `spring-native` module in +For more advanced or dynamic scenarios, you can still use **programmatic** configuration. The +`spring-native` module in this repository contains an example of this: - See `configureSampler` in - [`OpenTelemetryConfig`](../spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java) -- It uses `RuleBasedRoutingSampler` programmatically to drop spans for actuator endpoints (`/actuator*`), replicating + [ + `OpenTelemetryConfig`](../spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java) +- It uses `RuleBasedRoutingSampler` programmatically to drop spans for actuator endpoints ( + `/actuator*`), replicating the behavior we achieve declaratively via YAML in this module -In many cases, you can start with declarative configuration (as in this module) and only fall back to programmatic +In many cases, you can start with declarative configuration (as in this module) and only fall back +to programmatic customization for highly dynamic or application-specific logic. ## Troubleshooting and Tips @@ -254,23 +281,26 @@ customization for highly dynamic or application-specific logic. If the behavior is not what you expect, here are a few things to check: - **Health checks are still traced** - - Verify the `rules` section under `otel.tracer_provider.sampler.rule_based_routing` in `application.yaml` - - Ensure the `pattern` matches your actual actuator paths (e.g., `/actuator.*`) - - Confirm that `span_kind` is set to `SERVER` (or another correct span kind for your traffic) + - Verify the `rules` section under `otel.tracer_provider.sampler.rule_based_routing` in + `application.yaml` + - Ensure the `pattern` matches your actual actuator paths (e.g., `/actuator.*`) + - Confirm that `span_kind` is set to `SERVER` (or another correct span kind for your traffic) - **No spans are exported** - - Confirm that `otel.file_format` is set correctly (for example, `"1.0-rc.2"`) - - Check that at least one exporter is configured (e.g., `otlp_http` or `console`) - - Look for startup warnings or errors related to OpenTelemetry configuration + - Confirm that `otel.file_format` is set correctly (for example, `"1.0-rc.2"`) + - Check that at least one exporter is configured (e.g., `otlp_http` or `console`) + - Look for startup warnings or errors related to OpenTelemetry configuration - **Properties seem to be ignored** - - Make sure you are modifying the correct `application.yaml` for the active Spring profile - - Verify that all configuration keys are indented correctly under the `otel:` root - - Double-check that any placeholders use `:` for defaults (e.g., `${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}`) + - Make sure you are modifying the correct `application.yaml` for the active Spring profile + - Verify that all configuration keys are indented correctly under the `otel:` root + - Double-check that any placeholders use `:` for defaults (e.g., + `${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}`) If issues persist, compare your configuration to: - This module’s [`application.yaml`](./src/main/resources/application.yaml) -- The Java Agent example in [`javaagent-declarative-configuration`](../javaagent-declarative-configuration) +- The Java Agent example in [ + `javaagent-declarative-configuration`](../javaagent-declarative-configuration) - The reference schemas and examples in [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) From a7c01bcd2a031fd21862ea9d0dce60e8dd08ee7f Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 24 Nov 2025 10:22:23 +0100 Subject: [PATCH 09/11] manual review --- spring-declarative-configuration/README.md | 102 +++++---------------- 1 file changed, 24 insertions(+), 78 deletions(-) diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md index 84cfdf7283..28f9f31118 100644 --- a/spring-declarative-configuration/README.md +++ b/spring-declarative-configuration/README.md @@ -9,10 +9,6 @@ Instead of using the OpenTelemetry Java Agent, this module uses the [OpenTelemetry Spring Boot Starter](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/spring/spring-boot-autoconfigure) and configures declarative behavior via standard Spring Boot configuration in `application.yaml`. -> **Requirement:** Declarative configuration via the Spring Boot Starter requires version **2.22.0 -or newer** of the -> OpenTelemetry Spring Boot Starter. - The main configuration file for this example is: - [`src/main/resources/application.yaml`](./src/main/resources/application.yaml) @@ -21,8 +17,7 @@ For the underlying declarative configuration schema and additional examples, see [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) repository. Remember that when you copy examples from that repository into a Spring Boot app, you must nest them -under the -`otel:` root node (two-space indentation for all keys shown below). +under the `otel:` root node (two-space indentation for all keys shown below). This Spring Boot application includes two endpoints: @@ -36,12 +31,11 @@ This Spring Boot application includes two endpoints: - Java 17 or higher - OpenTelemetry Spring Boot Starter **2.22.0+** on the classpath of this application (already - configured in this - example’s build files) + configured in this example’s [build file](./build.gradle.kts)) ### Step 1: Build the Application -From the `spring-declarative-configuration` directory: +From this `spring-declarative-configuration` directory: ```bash ../gradlew bootJar @@ -96,8 +90,7 @@ listening on ## Declarative Configuration with Spring Boot -The declarative configuration used by this example lives in [ -`application.yaml`](./src/main/resources/application.yaml) +The declarative configuration used by this example lives in [`application.yaml`](./src/main/resources/application.yaml) under the `otel:` root key. ```yaml @@ -107,20 +100,17 @@ otel: This layout follows the declarative configuration schema defined in the [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) -repository, but adapted -for Spring Boot: +repository, but adapted for Spring Boot: - All OpenTelemetry configuration keys live under the `otel:` root - Configuration blocks from the reference repo (such as `tracer_provider`, `meter_provider`, - `logger_provider`, etc.) - are indented by **two spaces** beneath `otel:` + `logger_provider`, etc.) are indented by **two spaces** beneath `otel:` - The configuration is loaded via the OpenTelemetry Spring Boot Starter instead of the Java Agent ### Opting In with `file_format` Declarative configuration is **opt-in**. In this Spring Boot example, you enable declarative -configuration by setting -`file_format` under `otel:` in `application.yaml`: +configuration by setting `file_format` under `otel:` in `application.yaml`: ```yaml otel: @@ -135,36 +125,14 @@ If `file_format` is missing, declarative configuration is not applied. ### Example: Exporters and Sampler Rules (Spring Style) Below is a simplified view of the configuration used in this module. All keys are indented under -`otel:` as required by -Spring Boot declarative configuration. Refer to the actual +`otel:` as required by Spring Boot declarative configuration. Refer to the actual [`application.yaml`](./src/main/resources/application.yaml) for the complete version. ```yaml otel: file_format: "1.0-rc.2" - resource: - attributes: - - name: service.name - value: spring-boot-declarative-config-example - - propagator: - composite: - - tracecontext: - - baggage: - tracer_provider: - processors: - - batch: - exporter: - otlp_http: - # Note: Spring uses : instead of :- as separator for the default value - endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces - - - batch: - exporter: - console: - sampler: rule_based_routing: fallback_sampler: @@ -174,30 +142,13 @@ otel: - action: DROP attribute: url.path pattern: /actuator.* - - meter_provider: - readers: - - periodic: - exporter: - otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/metrics - - logger_provider: - processors: - - batch: - exporter: - otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/logs ``` -This configuration is conceptually equivalent to the Java Agent example’s `rule_based_routing` -sampler (from -`javaagent-declarative-configuration/otel-agent-config.yaml`): - -- It uses the `rule_based_routing` sampler contribution -- It restricts evaluation to `SERVER` spans -- It drops (`DROP`) spans whose `url.path` matches `/actuator.*` (e.g., `/actuator/health`) -- All other server requests are sampled by the `always_on` fallback sampler +This configuration: +- Uses the `rule_based_routing` sampler from the OpenTelemetry contrib extension +- Excludes health check endpoints (`/actuator.*`) from tracing using the `DROP` action +- Samples all other requests using the `always_on` fallback sampler +- Only applies to `SERVER` span kinds ## Spring Boot Starter–Specific Notes @@ -206,14 +157,13 @@ sampler (from - Declarative configuration is supported by the OpenTelemetry Spring Boot Starter starting with version **2.22.0** - Ensure your dependencies use at least this version; otherwise, `file_format` and other declarative - config features - may be ignored + config features may be ignored ### Property Metadata and IDE Auto-Completion Most IDEs derive auto-completion for Spring properties from Spring Boot configuration metadata. At -the time of this -example, that metadata is primarily based on the **non-declarative** configuration schema. +the time of this example, that metadata is primarily based on the **non-declarative** configuration +schema. As a result: @@ -247,15 +197,15 @@ otel: endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces ``` -Here, `http://localhost:4318` is used as the default if `OTEL_EXPORTER_OTLP_ENDPOINT` is not set. +Here, `http://localhost:4318` is used as the default if the `OTEL_EXPORTER_OTLP_ENDPOINT` +environment variable is not set. When copying configuration from non-Spring examples, always convert `:-` to `:` in placeholders. ## Declarative vs Programmatic Configuration Declarative configuration, as used in this example, allows you to express routing and sampling rules -entirely in -configuration files. This is ideal for: +entirely in configuration files. This is ideal for: - Operational teams that need to adjust sampling or filtering without changing code - Environments where configuration is managed externally (Kubernetes ConfigMaps, Spring Cloud @@ -266,15 +216,12 @@ For more advanced or dynamic scenarios, you can still use **programmatic** confi this repository contains an example of this: - See `configureSampler` in - [ - `OpenTelemetryConfig`](../spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java) -- It uses `RuleBasedRoutingSampler` programmatically to drop spans for actuator endpoints ( - `/actuator*`), replicating - the behavior we achieve declaratively via YAML in this module + [`OpenTelemetryConfig`](../spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java) +- It uses `RuleBasedRoutingSampler` programmatically to drop spans for actuator endpoints + (`/actuator*`), replicating the behavior we achieve declaratively via YAML in this module In many cases, you can start with declarative configuration (as in this module) and only fall back -to programmatic -customization for highly dynamic or application-specific logic. +to programmatic customization for highly dynamic or application-specific logic. ## Troubleshooting and Tips @@ -300,7 +247,6 @@ If the behavior is not what you expect, here are a few things to check: If issues persist, compare your configuration to: - This module’s [`application.yaml`](./src/main/resources/application.yaml) -- The Java Agent example in [ - `javaagent-declarative-configuration`](../javaagent-declarative-configuration) +- The Java Agent example in [`javaagent-declarative-configuration`](../javaagent-declarative-configuration) - The reference schemas and examples in [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) From a98046a605c53749a2b31e69826d1c3403c93695 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 24 Nov 2025 11:33:57 +0100 Subject: [PATCH 10/11] integrate with spring native --- .mise/tasks/oats-tests.sh | 5 ++--- spring-declarative-configuration/README.md | 25 ++++++++++++++++++++++ spring-native/build.gradle.kts | 2 +- spring-native/docker-compose.yml | 1 - 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.mise/tasks/oats-tests.sh b/.mise/tasks/oats-tests.sh index 4e831fc7a1..5a0507a246 100755 --- a/.mise/tasks/oats-tests.sh +++ b/.mise/tasks/oats-tests.sh @@ -15,6 +15,5 @@ pushd spring-declarative-configuration ../gradlew clean bootJar popd -oats -timeout 5m logging-k8s-stdout-otlp-json/ -oats -timeout 5m javaagent-declarative-configuration/oats/ -oats -timeout 5m spring-declarative-configuration/oats/ +# timeout for each test suite is 5 minutes +oats -timeout 5m . diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md index 28f9f31118..1d31bee024 100644 --- a/spring-declarative-configuration/README.md +++ b/spring-declarative-configuration/README.md @@ -250,3 +250,28 @@ If issues persist, compare your configuration to: - The Java Agent example in [`javaagent-declarative-configuration`](../javaagent-declarative-configuration) - The reference schemas and examples in [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) + +## Follow-up: applying the same pattern to Spring Native + +As a follow-up, you can reuse the ideas from this module to extend the `spring-native` example +with declarative configuration and a Collector running via Docker Compose: + +- Start from the `spring-native` module in this repository. +- delete the `application.properties` file in `spring-native/src/main/resources/` +- copy `application.yaml` from this module to `spring-native/src/main/resources/` +- add the settings from `application.properties` back into that `application.yaml` +- follow the instructions in [spring-native/README.md](../spring-native/README.md) to run with + Docker Compose + +```shell +rm ../spring-native/src/main/resources/application.properties +cp src/main/resources/application.yaml ../spring-native/src/main/resources/ +echo "spring: + datasource: + url: jdbc:h2:mem:db +management: + endpoints: + web: + exposure: + include: '*'" >> ../spring-native/src/main/resources/application.yaml +``` diff --git a/spring-native/build.gradle.kts b/spring-native/build.gradle.kts index 467ab5359b..9666f3dd08 100644 --- a/spring-native/build.gradle.kts +++ b/spring-native/build.gradle.kts @@ -2,7 +2,7 @@ import org.springframework.boot.gradle.plugin.SpringBootPlugin plugins { id("java") - id("org.springframework.boot") version "3.5.7" + id("org.springframework.boot") version "3.5.8" id("org.graalvm.buildtools.native") version "0.11.3" } diff --git a/spring-native/docker-compose.yml b/spring-native/docker-compose.yml index 6de788142b..fb8ff56c4d 100644 --- a/spring-native/docker-compose.yml +++ b/spring-native/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.8' services: app: image: otel-native-graalvm From 4a3d68de1021e518a2372d14b5daecdd4471e2bc Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 25 Nov 2025 11:51:23 +0100 Subject: [PATCH 11/11] add note --- spring-declarative-configuration/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spring-declarative-configuration/README.md b/spring-declarative-configuration/README.md index 1d31bee024..4642a625d7 100644 --- a/spring-declarative-configuration/README.md +++ b/spring-declarative-configuration/README.md @@ -263,6 +263,10 @@ with declarative configuration and a Collector running via Docker Compose: - follow the instructions in [spring-native/README.md](../spring-native/README.md) to run with Docker Compose +Note that `OpenTelemetryConfig.otelCustomizer` is being ignored in this case, since we are using +declarative configuration now, which uses `DeclarativeConfigurationCustomizerProvider` instead of +`AutoConfigurationCustomizerProvider`. + ```shell rm ../spring-native/src/main/resources/application.properties cp src/main/resources/application.yaml ../spring-native/src/main/resources/