Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/scripts/run-oats-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ pushd logging-k8s-stdout-otlp-json
../gradlew assemble
popd

pushd javaagent-declarative-configuration
../gradlew bootJar
popd

wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash

go install github.com/grafana/[email protected]
oats -timeout 5m logging-k8s-stdout-otlp-json/
oats -timeout 5m javaagent-declarative-configuration/
1 change: 1 addition & 0 deletions .github/workflows/oats-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
paths:
- .github/workflows/oats-tests.yml
- 'logging-k8s-stdout-otlp-json/**'
- 'javaagent-declarative-configuration/**'
workflow_dispatch:

permissions:
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ bin
.swp

# Polyglot runtime manager (asdf rust clone)
.rtx.toml
.rtx.toml


javaagent-declarative-configuration/opentelemetry-javaagent.jar
javaagent-declarative-configuration/opentelemetry-javaagent-extension.jar
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could move these into javaagent-declarative-configuration/.gitignore

15 changes: 15 additions & 0 deletions javaagent-declarative-configuration/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM eclipse-temurin:21.0.8_9-jre@sha256:615497e30ae2b2654ff7bccc7cb057c27443041994593c726852f04dc99830b1

WORKDIR /usr/src/app/

# renovate: datasource=github-releases depName=opentelemetry-java-instrumentation packageName=open-telemetry/opentelemetry-java-instrumentation
ENV OPENTELEMETRY_JAVA_INSTRUMENTATION_VERSION=v2.21.0

ADD build/libs/javaagent-declarative-configuration.jar ./app.jar
ADD --chmod=644 https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/$OPENTELEMETRY_JAVA_INSTRUMENTATION_VERSION/opentelemetry-javaagent.jar ./opentelemetry-javaagent.jar
ADD otel-agent-config.yaml ./otel-agent-config.yaml
ENV JAVA_TOOL_OPTIONS=-javaagent:./opentelemetry-javaagent.jar
ENV OTEL_EXPERIMENTAL_CONFIG_FILE=/usr/src/app/otel-agent-config.yaml

EXPOSE 8080
ENTRYPOINT [ "java", "-jar", "./app.jar" ]
80 changes: 80 additions & 0 deletions javaagent-declarative-configuration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Java Agent Declarative Configuration Example

This example demonstrates how to use [declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) with the OpenTelemetry Java Agent to configure tracing behavior.

The configuration file is located at [otel-agent-config.yaml](./otel-agent-config.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 Java Agent JAR file (see next step)

Download the OpenTelemetry Java Agent:
```bash
# Download the latest OpenTelemetry Java Agent
curl -L -o opentelemetry-javaagent.jar https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
```

### Step 1: Build the Application

```bash
# Build the JAR - Run from the javaagent-declarative-configuration directory
../gradlew bootJar
```

### Step 2: Run with OpenTelemetry Java Agent

```bash
# From the javaagent-declarative-configuration directory

# Run with the OpenTelemetry Java Agent and contrib extension
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.experimental.config.file=$(pwd)/otel-agent-config.yaml \
-jar build/libs/javaagent-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 the application logs to see:
- Health check requests (`/actuator/health`) should NOT generate traces (excluded by configuration)
- API requests (`/api/example`) should generate traces with console output

## Configuration

The `otel-agent-config.yaml` file demonstrates rule-based sampling using declarative configuration to exclude health checks from tracing:

```yaml
tracer_provider:
sampler:
rule_based_routing:
fallback_sampler:
always_on:
span_kind: SERVER
rules:
- action: DROP
attribute: url.path
pattern: /actuator.*
```

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
20 changes: 20 additions & 0 deletions javaagent-declarative-configuration/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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.6"
}

description = "OpenTelemetry Java Agent Declarative Configuration Example"
val moduleName by extra { "io.opentelemetry.examples.javaagent.declarative" }

dependencies {
implementation(platform(SpringBootPlugin.BOM_COORDINATES))
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
}

tasks.named<BootJar>("bootJar") {
archiveFileName = "javaagent-declarative-configuration.jar"
}
16 changes: 16 additions & 0 deletions javaagent-declarative-configuration/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3'
services:
app:
build: ./
environment:
OTEL_SERVICE_NAME: "declarative-config-example-app"
OTEL_EXPORTER_OTLP_ENDPOINT: http://lgtm:4318
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: http://lgtm:4318
OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
ports:
- "8080:8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 10s
timeout: 5s
retries: 3
26 changes: 26 additions & 0 deletions javaagent-declarative-configuration/oats.yaml
Original file line number Diff line number Diff line change
@@ -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"
55 changes: 55 additions & 0 deletions javaagent-declarative-configuration/otel-agent-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# See https://github.com/open-telemetry/opentelemetry-configuration for details on schema and examples

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_TRACES_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_METRICS_ENDPOINT:-http://localhost:4318}/v1/metrics

logger_provider:
processors:
- batch:
exporter:
otlp_http:
endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/logs
Original file line number Diff line number Diff line change
@@ -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<String> example() {
return ResponseEntity.ok("Hello from OpenTelemetry example API!");
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
10 changes: 0 additions & 10 deletions javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ java {
}

val agent = configurations.create("agent")
val extension = configurations.create("extension")

dependencies {
implementation(platform(SpringBootPlugin.BOM_COORDINATES))
Expand All @@ -27,9 +26,6 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")

agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.21.0")
extension("io.opentelemetry.contrib:opentelemetry-samplers:1.50.0-alpha") {
isTransitive = false
}
}

val copyAgent = tasks.register<Copy>("copyAgent") {
Expand All @@ -38,15 +34,9 @@ val copyAgent = tasks.register<Copy>("copyAgent") {
rename("opentelemetry-javaagent-.*\\.jar", "opentelemetry-javaagent.jar")
}

val copyExtension = tasks.register<Copy>("copyExtension") {
from(extension.singleFile)
into(layout.buildDirectory.dir("agent"))
rename(".*\\.jar", "opentelemetry-javaagent-extension.jar")
}

tasks.named<BootJar>("bootJar") {
dependsOn(copyAgent)
dependsOn(copyExtension)

archiveFileName = "app.jar"
}
8 changes: 5 additions & 3 deletions javaagent/sdk-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copy of https://github.com/open-telemetry/opentelemetry-configuration/blob/v0.3.0/examples/sdk-config.yaml
# Copy of https://github.com/open-telemetry/opentelemetry-configuration/blob/v1.0.0-rc.2/examples/sdk-config.yaml
# with the following changes:
# - OpenTelemetry Java Agent properties added at .instrumentation.java.
# - OTLP exporter endpoints modified to point to http://collector:4318/v1/{path} to export to collector from docker-compose.yml
Expand All @@ -13,7 +13,7 @@
# vars defined in https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/.

# The file format version.
file_format: "0.3"
file_format: "1.0-rc.2"

# Configure if the SDK is disabled or not. This is not required to be provided to ensure the SDK isn't disabled, the default value when this is not provided is for the SDK to be enabled.
disabled: false
Expand All @@ -36,7 +36,9 @@ attribute_limits:
# Configure text map context propagators.
propagator:
# Configure the set of propagators to include in the composite text map propagator.
composite: [ tracecontext, baggage ]
composite:
- tracecontext:
- baggage:

# Configure tracer provider.
tracer_provider:
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ rootProject.name = "opentelemetry-java-examples"
include(
":opentelemetry-examples-autoconfigure",
":opentelemetry-examples-declarative-configuration",
":opentelemetry-examples-javaagent-declarative-configuration",
":opentelemetry-examples-http",
":opentelemetry-examples-jaeger",
":opentelemetry-examples-javaagent",
Expand Down
Loading