Skip to content

Commit 98d2ccd

Browse files
Migrate to OpenTelemetry Java agent for automatic instrumentation (#590)
* Migrate to OpenTelemetry Java agent for automatic instrumentation Replaces manual instrumentation with the OTel Java agent (v2.26.0). Removes manual instrumentation libraries for AWS SDK, OkHttp, and Logback. The agent automatically instruments these libraries without code changes. Changes: - Add OTel agent download and distribution to all deployment paths - Upgrade OTel SDK from 1.45.0 to 1.60.1 - Remove manual instrumentation dependencies and code - Simplify AWS client configuration (agent handles tracing) - Remove Logback OTel appender (agent handles log export) All deployment paths now use the agent: development, distribution, and containers. * Remove manual OpenTelemetry instrumentation The OpenTelemetry Java agent handles all instrumentation automatically. Manual instrumentation is redundant and creates version conflicts. Changes: - Remove opentelemetry-sdk-extension-autoconfigure dependency (conflicts with agent) - Remove all OpenTelemetry SDK dependencies from libs.versions.toml - Delete entire observability/ package (TelemetryProvider, OtelTelemetryProvider, etc.) - Remove all manual instrumentation calls (withSpan, recordDuration, incrementCounter) - Remove telemetryProvider from DefaultRemoteOperationsService, CommandExecutor, K8s services - Remove unused telemetryProvider parameter from AWSModule and AWSClientFactory - Update all tests to remove TelemetryProvider mocks The Java agent now handles all instrumentation: AWS SDK, HTTP clients, JDBC/Cassandra driver, JVM metrics, and logging. * Use version catalog for opentelemetry-javaagent dependency Instead of hardcoding the version in build.gradle.kts, reference the opentelemetry-agent version from libs.versions.toml to avoid drift. * Update OpenTelemetry documentation for agent-only approach Rewrites docs/reference/opentelemetry.md to reflect the removal of manual instrumentation. Key changes: - Clarifies that the agent is always loaded but only exports telemetry when OTEL_EXPORTER_OTLP_ENDPOINT is set (minimal overhead when unset) - Removes "Instrumented Operations" section describing deleted custom spans - Removes "Metrics" table listing deleted custom metrics - Removes "Shutdown Warnings" troubleshooting entry for deleted shutdown hook - Emphasizes "automatic instrumentation only - there is no custom manual instrumentation in the CLI tool code" Updates CLAUDE.md to remove outdated reference to deleted observability/ package and replace with accurate description of Java agent-based automatic instrumentation. * Fix OTLP endpoint configuration in end-to-end tests Configures the OpenTelemetry Java agent to use gRPC protocol when connecting to the OTLP collector in docker compose. The agent was defaulting to HTTP protocol and attempting to append paths to the endpoint, causing "unexpected end of stream" errors. Changes: - Discover OTLP collector port from docker compose using `port` command - Export OTEL_EXPORTER_OTLP_ENDPOINT with the discovered port mapping - Export OTEL_EXPORTER_OTLP_PROTOCOL=grpc to force gRPC protocol This ensures tests can successfully export telemetry to the local collector without connection errors. * Suppress logging output to prevent pollution of machine-readable stdout Commands like `show-iam-policies` (sip) output JSON that's consumed by shell scripts. kotlin-logging initialization messages and OpenTelemetry agent logs were polluting stdout, causing AWS IAM to reject the output as malformed JSON. Changes: - Make Main.kt logger lazy and suppress kotlin-logging startup message - Route OTel agent logs through logback instead of stdout - Use consistent agent path in bin/easy-db-lab (installDist location) This ensures commands can safely redirect stdout for machine parsing. * Suppress JVM Class Data Sharing warning Add -Xshare:off to suppress "Sharing is only supported for boot loader classes because bootstrap classpath has been appended" warning that occurs when using the OpenTelemetry javaagent.
1 parent 4ec42d2 commit 98d2ccd

31 files changed

+197
-1113
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ All observability K8s resources are built programmatically using Fabric8 manifes
285285

286286
**Grafana** (port 3000): Dashboards built via `GrafanaManifestBuilder`. Dashboard JSON in `configuration/grafana/dashboards/` with `__KEY__` template substitution. `GrafanaDashboard` enum is the single source of truth for dashboard metadata.
287287

288-
**OTel Instrumentation in Kotlin**: The `observability/` package provides `TelemetryProvider` with `withSpan()`, `recordDuration()`, `incrementCounter()`. See `docs/reference/opentelemetry.md`.
288+
**CLI Tool Instrumentation**: The CLI tool uses the OpenTelemetry Java Agent for automatic instrumentation of AWS SDK calls, HTTP clients, JDBC operations, and JVM metrics. No manual instrumentation exists in the Kotlin code. See `docs/reference/opentelemetry.md`.
289289

290290
**CLI commands**: `grafana update-config`, `logs query/backup/import/ls`, `metrics backup/import/ls`
291291

bin/easy-db-lab

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ EASY_DB_LAB_USER_DATA=~/.easy-db-lab/
1212
VERSION=$(grep '^version' "${APP_HOME}/gradle.properties" | cut -d '=' -f2)
1313

1414
JAR="${APP_HOME}/build/libs/easy-db-lab-${VERSION}-all.jar"
15+
OTEL_AGENT="${APP_HOME}/build/install/easy-db-lab/agents/opentelemetry-javaagent.jar"
1516

1617
# Start OTel collector
1718
if [ "${EASY_DB_LAB_SKIP_DOCKER}" != "1" ]; then
@@ -26,4 +27,8 @@ OTEL_PORT=$(docker compose -f "${APP_HOME}/docker-compose.yml" port otel-collect
2627
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${OTEL_PORT}"
2728
export EASY_DB_LAB_REDIS_URL="redis://localhost:6399/easydblab-events"
2829

29-
java -Deasydblab.version=$VERSION -Deasydblab.apphome=$APP_HOME -jar $JAR "$@"
30+
# Route OTel agent logs through application logger (logback) instead of stdout
31+
# This prevents agent messages from polluting machine-readable output (like JSON policies)
32+
export OTEL_JAVAAGENT_LOGGING=application
33+
34+
java -Xshare:off -Deasydblab.version=$VERSION -Deasydblab.apphome=$APP_HOME -javaagent:"$OTEL_AGENT" -jar $JAR "$@"

bin/end-to-end-test

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,13 @@ export EASY_DB_LAB_SKIP_BUILD=1
14571457

14581458
# Start Docker services once upfront (Redis, OTel collector), then skip per-invocation restarts
14591459
docker compose -f "$PROJECT_ROOT/docker-compose.yml" up -d
1460+
1461+
# Discover the dynamically assigned OTLP port and export for test execution
1462+
OTEL_PORT=$(docker compose -f "$PROJECT_ROOT/docker-compose.yml" port otel-collector 4317 2>/dev/null | cut -d: -f2)
1463+
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${OTEL_PORT}"
1464+
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
1465+
echo "OpenTelemetry OTLP endpoint: $OTEL_EXPORTER_OTLP_ENDPOINT (protocol: grpc)"
1466+
14601467
export EASY_DB_LAB_SKIP_DOCKER=1
14611468

14621469
# Change to work directory

build.gradle.kts

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,23 @@ plugins {
2121
alias(libs.plugins.ktor)
2222
}
2323

24+
// Configuration for OpenTelemetry Java agent
25+
val otelAgentConfig: Configuration by configurations.creating {
26+
isCanBeConsumed = false
27+
isCanBeResolved = true
28+
}
29+
30+
val copyOtelAgent =
31+
tasks.register<Copy>("copyOtelAgent") {
32+
from(otelAgentConfig)
33+
into("${project.layout.buildDirectory.get()}/otel-agent")
34+
rename { "opentelemetry-javaagent.jar" }
35+
}
36+
37+
dependencies {
38+
otelAgentConfig("io.opentelemetry.javaagent:opentelemetry-javaagent:${libs.versions.opentelemetry.agent.get()}")
39+
}
40+
2441
group = "com.rustyrazorblade"
2542

2643
tasks.withType<ShadowJar> {
@@ -36,6 +53,7 @@ application {
3653
mainClass.set("com.rustyrazorblade.easydblab.MainKt")
3754
applicationDefaultJvmArgs =
3855
listOf(
56+
"-javaagent:\$APP_HOME/agents/opentelemetry-javaagent.jar",
3957
"-Deasydblab.ami.name=rustyrazorblade/images/easy-db-lab-cassandra-amd64-$version",
4058
"-Deasydblab.version=$version",
4159
)
@@ -64,14 +82,6 @@ tasks.named<CreateStartScripts>("startScripts") {
6482
}
6583
}
6684

67-
// Force OpenTelemetry incubator versions before Gradle upgrades them
68-
configurations.all {
69-
resolutionStrategy {
70-
force("io.opentelemetry:opentelemetry-api-incubator:1.45.0-alpha")
71-
force("io.opentelemetry:opentelemetry-sdk-extension-incubator:1.45.0-alpha")
72-
}
73-
}
74-
7585
// In this section you declare the dependencies for your production and test code
7686
dependencies {
7787
// Logging
@@ -137,9 +147,6 @@ dependencies {
137147
// Cassandra Driver
138148
implementation(libs.cassandra.driver.core)
139149

140-
// OpenTelemetry
141-
implementation(libs.bundles.opentelemetry)
142-
143150
// Testing
144151
testImplementation(libs.bundles.testing)
145152
testImplementation(libs.bundles.koin.test)
@@ -241,6 +248,10 @@ distributions {
241248
from("packer") {
242249
into("packer")
243250
}
251+
// Include the OTel agent in the distribution
252+
from(copyOtelAgent) {
253+
into("agents")
254+
}
244255
}
245256
}
246257
}
@@ -251,7 +262,14 @@ tasks.distTar {
251262
}
252263

253264
tasks.named("installDist") {
254-
dependsOn(tasks.named("shadowJar"))
265+
dependsOn(tasks.named("shadowJar"), copyOtelAgent)
266+
doLast {
267+
// Copy agent to installDist location
268+
copy {
269+
from("${project.layout.buildDirectory.get()}/otel-agent")
270+
into(layout.buildDirectory.dir("install/easy-db-lab/agents"))
271+
}
272+
}
255273
}
256274

257275
tasks.assemble {
@@ -330,6 +348,7 @@ jib {
330348
appRoot = "/app"
331349
jvmFlags =
332350
listOf(
351+
"-javaagent:/agents/opentelemetry-javaagent.jar",
333352
"-Deasydblab.ami.name=rustyrazorblade/images/easy-db-lab-cassandra-amd64-$version",
334353
"-Deasydblab.version=$version",
335354
"-Deasydblab.apphome=/app",
@@ -345,6 +364,10 @@ jib {
345364
setFrom(file("packer"))
346365
into = "/app/packer"
347366
}
367+
path {
368+
setFrom("${project.layout.buildDirectory.get()}/otel-agent")
369+
into = "/agents"
370+
}
348371
}
349372
}
350373
creationTime = "USE_CURRENT_TIMESTAMP"
@@ -364,9 +387,11 @@ jib {
364387

365388
// Jib doesn't fully support configuration cache yet
366389
tasks.named("jib") {
390+
dependsOn(copyOtelAgent)
367391
notCompatibleWithConfigurationCache("Jib plugin doesn't fully support configuration cache yet")
368392
}
369393

370394
tasks.named("jibDockerBuild") {
395+
dependsOn(copyOtelAgent)
371396
notCompatibleWithConfigurationCache("Jib plugin doesn't fully support configuration cache yet")
372397
}

docs/reference/opentelemetry.md

Lines changed: 32 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@
22

33
easy-db-lab includes optional OpenTelemetry (OTel) instrumentation for distributed tracing and metrics. When enabled, traces and metrics are exported to an OTLP-compatible collector.
44

5-
## Enabling OpenTelemetry
5+
## CLI Tool Instrumentation
6+
7+
The easy-db-lab CLI tool runs with the OpenTelemetry Java Agent, which automatically instruments:
8+
9+
- **AWS SDK calls** - EC2, S3, IAM, EMR, STS, OpenSearch operations
10+
- **HTTP clients** - OkHttp and other HTTP libraries
11+
- **JDBC/Cassandra driver** - Database operations
12+
- **JVM metrics** - Memory, threads, garbage collection
13+
14+
### Enabling Instrumentation
615

716
Set the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable to your OTLP collector endpoint:
817

@@ -13,52 +22,15 @@ easy-db-lab up
1322

1423
When this environment variable is:
1524
- **Set**: Traces and metrics are exported via gRPC to the specified endpoint
16-
- **Not set**: OpenTelemetry is completely disabled with zero overhead
17-
18-
## Instrumented Operations
19-
20-
### Commands
21-
22-
All CLI commands are automatically instrumented with:
23-
- A span for each command execution
24-
- Duration metrics
25-
- Command count metrics
26-
- Success/failure attributes
25+
- **Not set**: The agent is still loaded but no telemetry is exported (minimal overhead)
2726

28-
### SSH Operations
27+
The agent uses automatic instrumentation only - there is no custom manual instrumentation in the CLI tool code.
2928

30-
Remote SSH operations are instrumented including:
31-
- Command execution (`ssh.execute`)
32-
- File uploads (`ssh.upload`, `ssh.upload_directory`)
33-
- File downloads (`ssh.download`, `ssh.download_directory`)
29+
## Cluster Node Instrumentation
3430

35-
Span attributes include host alias, target IP, and (for non-secret commands) the command text.
31+
The following instrumentation applies to cluster nodes (Cassandra, stress, Spark) and is separate from the CLI tool:
3632

37-
### Kubernetes Operations
38-
39-
K8s operations via the fabric8 client are instrumented:
40-
- Manifest application (`k8s.apply_manifests`, `k8s.apply_yaml`)
41-
- Namespace deletion (`k8s.delete_namespace`)
42-
- StatefulSet scaling (`k8s.scale_statefulset`)
43-
44-
### AWS SDK Calls
45-
46-
When OTel is enabled, AWS SDK calls are automatically instrumented using the OpenTelemetry AWS SDK instrumentation library. This includes:
47-
- EC2 operations
48-
- S3 operations
49-
- IAM operations
50-
- EMR operations
51-
- STS operations
52-
- OpenSearch operations
53-
54-
## Resource Attributes
55-
56-
Traces include the following resource attributes:
57-
- `service.name`: `easy-db-lab`
58-
- `service.version`: Application version
59-
- `host.name`: Local hostname
60-
61-
## Node Role Labeling
33+
### Node Role Labeling
6234

6335
The OTel Collector on cluster nodes uses the `k8sattributes` processor to read the K8s node label `type` and set it as the `node_role` resource attribute. This label is used by Grafana dashboards (e.g., System Overview) for hostname and service filtering.
6436

@@ -73,20 +45,7 @@ The `k8sattributes` processor runs in the `metrics/local` and `logs/local` pipel
7345

7446
The processor requires RBAC access to the K8s API. The OTel Collector DaemonSet runs with a dedicated ServiceAccount (`otel-collector`) that has read-only access to pods and nodes.
7547

76-
## Metrics
77-
78-
The following metrics are exported:
79-
80-
| Metric | Type | Description |
81-
|--------|------|-------------|
82-
| `easydblab.command.duration` | Histogram | Command execution duration (ms) |
83-
| `easydblab.command.count` | Counter | Number of commands executed |
84-
| `easydblab.ssh.operation.duration` | Histogram | SSH operation duration (ms) |
85-
| `easydblab.ssh.operation.count` | Counter | Number of SSH operations |
86-
| `easydblab.k8s.operation.duration` | Histogram | K8s operation duration (ms) |
87-
| `easydblab.k8s.operation.count` | Counter | Number of K8s operations |
88-
89-
## Stress Job Metrics
48+
### Stress Job Metrics
9049

9150
When running cassandra-easy-stress as K8s Jobs, metrics are automatically collected via an OTel collector sidecar container. The sidecar scrapes the stress process's Prometheus endpoint (`localhost:9500`) and forwards metrics via OTLP to the node's OTel DaemonSet, which then exports them to VictoriaMetrics.
9251

@@ -100,7 +59,7 @@ The Prometheus scrape job is named `cassandra-easy-stress`. The following labels
10059

10160
Short-lived stress commands (`list`, `info`, `fields`) do not include the sidecar since they complete quickly and don't produce meaningful metrics.
10261

103-
## Spark JVM Instrumentation
62+
### Spark JVM Instrumentation
10463

10564
EMR Spark jobs are auto-instrumented with the OpenTelemetry Java Agent (v2.25.0) and Pyroscope Java Agent (v2.3.0), both installed via an EMR bootstrap action. The OTel agent is activated through `spark.driver.extraJavaOptions` and `spark.executor.extraJavaOptions`.
10665

@@ -115,7 +74,7 @@ Key configuration:
11574
- **Service name**: `spark-<job-name>` (set per job)
11675
- **Profiling**: CPU, allocation (512k threshold), lock (10ms threshold) profiles in JFR format sent to Pyroscope server
11776

118-
## Cassandra Sidecar Instrumentation
77+
### Cassandra Sidecar Instrumentation
11978

12079
The Cassandra Sidecar process is instrumented with the OpenTelemetry Java Agent and Pyroscope Java Agent, matching the pattern used for Cassandra itself. Both agents are loaded via `-javaagent` flags set in `/etc/default/cassandra-sidecar`, which is written by the `setup-instances` command.
12180

@@ -127,7 +86,7 @@ Key configuration:
12786
- **Profiling**: CPU, allocation (512k threshold), lock (10ms threshold) profiles sent to Pyroscope server
12887
- **Activation**: Gated on `/etc/default/cassandra-sidecar` — the systemd `EnvironmentFile=-` directive makes it optional, so the sidecar starts normally without instrumentation if the file doesn't exist
12988

130-
## Tool Runner Log Collection
89+
### Tool Runner Log Collection
13190

13291
Commands run via `exec run` are executed through `systemd-run`, which captures stdout and stderr to log files under `/var/log/easydblab/tools/`. The OTel Collector's `filelog/tools` receiver watches this directory and ships log entries to VictoriaLogs with the attribute `source: tool-runner`.
13392

@@ -139,7 +98,7 @@ Key details:
13998
- **Foreground commands**: Output displayed after completion, also logged to file
14099
- **Background commands** (`--bg`): Output logged to file only, tool runs as a systemd transient unit
141100

142-
## YACE CloudWatch Scrape
101+
### YACE CloudWatch Scrape
143102

144103
YACE (Yet Another CloudWatch Exporter) runs on the control node and scrapes AWS CloudWatch metrics for services used by the cluster. It uses tag-based auto-discovery with the `easy_cass_lab=1` tag to find relevant resources.
145104

@@ -153,15 +112,24 @@ EMR metrics are collected directly via OTel Collectors on Spark nodes (see Spark
153112

154113
YACE exposes scraped metrics as Prometheus-compatible metrics on port 5001, which are then scraped by the OTel Collector and forwarded to VictoriaMetrics. This replaces the previous CloudWatch datasource in Grafana with a Prometheus-based approach, giving dashboards access to CloudWatch metrics through VictoriaMetrics queries.
155114

115+
## Resource Attributes
116+
117+
Traces from the CLI tool and cluster nodes include the following resource attributes:
118+
- `service.name`: Service identifier (e.g., `easy-db-lab`, `cassandra-sidecar`, `spark-<job-name>`)
119+
- `service.version`: Application version (CLI tool only)
120+
- `host.name`: Hostname
121+
156122
## Configuration
157123

158124
The following environment variables are supported:
159125

160126
| Variable | Description | Default |
161127
|----------|-------------|---------|
162-
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP gRPC endpoint | None (OTel disabled) |
128+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP gRPC endpoint | None (no export) |
129+
| `OTEL_SERVICE_NAME` | Override service name | `easy-db-lab` |
130+
| `OTEL_RESOURCE_ATTRIBUTES` | Additional resource attributes | None |
163131

164-
Additional standard OTel environment variables may work depending on the SDK defaults.
132+
Additional standard OTel environment variables are supported by the agent. See the [OpenTelemetry Java Agent documentation](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/) for details.
165133

166134
## Example: Using with Jaeger
167135

@@ -198,12 +166,8 @@ easy-db-lab up
198166

199167
1. Verify the endpoint is correct and reachable
200168
2. Check that the collector accepts gRPC OTLP (port 4317 is standard)
201-
3. Look for OpenTelemetry initialization logs on startup
169+
3. Look for OpenTelemetry agent logs on startup (use `-Dotel.javaagent.debug=true` to enable debug logging)
202170

203171
### High Latency
204172

205173
Traces are batched before export (default 1 second delay). This is normal and reduces overhead.
206-
207-
### Shutdown Warnings
208-
209-
A shutdown hook flushes remaining telemetry on exit. Brief delays during shutdown are expected.

gradle/libs.versions.toml

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ resilience4j = "2.4.0"
6666
fabric8-kubernetes = "7.5.0"
6767

6868
# OpenTelemetry
69-
opentelemetry = "1.45.0"
70-
opentelemetry-instrumentation = "2.26.0-alpha"
71-
opentelemetry-semconv = "1.29.0-alpha"
69+
opentelemetry-agent = "2.26.0"
7270

7371
# Gradle Plugins
7472
shadow = "9.3.2"
@@ -172,18 +170,6 @@ fabric8-kubernetes-client = { module = "io.fabric8:kubernetes-client", version.r
172170
# Cassandra Driver
173171
cassandra-driver-core = { module = "org.apache.cassandra:java-driver-core", version.ref = "cassandra-driver" }
174172

175-
# OpenTelemetry
176-
opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref = "opentelemetry" }
177-
opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk", version.ref = "opentelemetry" }
178-
opentelemetry-sdk-extension-autoconfigure = { module = "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure", version.ref = "opentelemetry" }
179-
opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp", version.ref = "opentelemetry" }
180-
opentelemetry-api-incubator = { module = "io.opentelemetry:opentelemetry-api-incubator", version = "1.45.0-alpha" }
181-
opentelemetry-sdk-extension-incubator = { module = "io.opentelemetry:opentelemetry-sdk-extension-incubator", version = "1.45.0-alpha" }
182-
opentelemetry-semconv = { module = "io.opentelemetry.semconv:opentelemetry-semconv", version.ref = "opentelemetry-semconv" }
183-
opentelemetry-semconv-incubating = { module = "io.opentelemetry.semconv:opentelemetry-semconv-incubating", version.ref = "opentelemetry-semconv" }
184-
opentelemetry-instrumentation-logback = { module = "io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0", version.ref = "opentelemetry-instrumentation" }
185-
opentelemetry-aws-sdk = { module = "io.opentelemetry.instrumentation:opentelemetry-aws-sdk-2.2", version.ref = "opentelemetry-instrumentation" }
186-
opentelemetry-okhttp = { module = "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0", version.ref = "opentelemetry-instrumentation" }
187173

188174
[bundles]
189175
# Logging bundle
@@ -217,8 +203,6 @@ sshd = ["sshd-core", "sshd-scp"]
217203
# Resilience4j bundle
218204
resilience4j = ["resilience4j-retry", "resilience4j-kotlin"]
219205

220-
# OpenTelemetry bundle
221-
opentelemetry = ["opentelemetry-api", "opentelemetry-api-incubator", "opentelemetry-sdk", "opentelemetry-sdk-extension-autoconfigure", "opentelemetry-sdk-extension-incubator", "opentelemetry-exporter-otlp", "opentelemetry-aws-sdk", "opentelemetry-okhttp", "opentelemetry-instrumentation-logback"]
222206

223207
[plugins]
224208
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }

0 commit comments

Comments
 (0)