Skip to content

Commit 9915090

Browse files
authored
Merge branch 'main' into main
2 parents cd86d60 + 8e0b613 commit 9915090

File tree

26 files changed

+1352
-82
lines changed

26 files changed

+1352
-82
lines changed

benchmark-overhead/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
plugins {
22
id("java")
3-
id("com.diffplug.spotless") version "7.2.1"
3+
id("com.diffplug.spotless") version "8.0.0"
44
}
55

66
spotless {

conventions/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
plugins {
22
`kotlin-dsl`
33
// When updating, update below in dependencies too
4-
id("com.diffplug.spotless") version "7.2.1"
4+
id("com.diffplug.spotless") version "8.0.0"
55
}
66

77
spotless {
@@ -54,7 +54,7 @@ dependencies {
5454
implementation("org.apache.maven:maven-aether-provider:3.3.9")
5555

5656
// When updating, update above in plugins too
57-
implementation("com.diffplug.spotless:spotless-plugin-gradle:7.2.1")
57+
implementation("com.diffplug.spotless:spotless-plugin-gradle:8.0.0")
5858
implementation("com.google.guava:guava:33.5.0-jre")
5959
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.2.1")
6060
implementation("org.apache.httpcomponents:httpclient:4.5.14")

custom-checks/src/test/java/io/opentelemetry/javaagent/customchecks/OtelInternalJavadocTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class OtelInternalJavadocTest {
1414
void test() {
1515
doTest(
1616
"internal/InternalJavadocPositiveCases.java",
17-
"""
17+
"""
1818
package io.opentelemetry.javaagent.customchecks.internal;
1919
2020
// BUG: Diagnostic contains: doesn't end with any of the applicable javadoc disclaimers
@@ -30,7 +30,7 @@ public static class Two {}
3030
""");
3131
doTest(
3232
"internal/InternalJavadocNegativeCases.java",
33-
"""
33+
"""
3434
package io.opentelemetry.javaagent.customchecks.internal;
3535
3636
/**

docs/contributing/documenting-instrumentation.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,22 @@ configurations:
9696
description: Enables statement sanitization for database queries.
9797
type: boolean
9898
default: true
99+
override_telemetry: false
100+
additional_telemetry:
101+
- when: "default"
102+
metrics:
103+
- name: "metric.name"
104+
description: "Metric description"
105+
type: "COUNTER"
106+
unit: "1"
107+
attributes:
108+
- name: "attribute.name"
109+
type: "STRING"
110+
spans:
111+
- span_kind: "CLIENT"
112+
attributes:
113+
- name: "span.attribute"
114+
type: "STRING"
99115
```
100116
101117
### Description (required)
@@ -205,6 +221,82 @@ If an instrumentation is disabled by default, set `disabled_by_default: true`. T
205221
the instrumentation will not be active unless explicitly enabled by the user. If this field is omitted,
206222
it defaults to `false`, meaning the instrumentation is enabled by default.
207223

224+
### Manual Telemetry Documentation (optional)
225+
226+
You can manually document telemetry metadata (metrics and spans) directly in the `metadata.yaml` file
227+
using the `additional_telemetry` field. This is useful for:
228+
229+
- Documenting telemetry that may not be captured during automated test runs
230+
- Adding telemetry documentation when `.telemetry` files are not available
231+
- Providing additional context or details about emitted telemetry
232+
233+
#### additional_telemetry
234+
235+
The `additional_telemetry` field allows you to specify telemetry metadata organized by configuration
236+
conditions (`when` field):
237+
238+
```yaml
239+
additional_telemetry:
240+
- when: "default" # Telemetry emitted by default
241+
metrics:
242+
- name: "http.server.request.duration"
243+
description: "Duration of HTTP server requests"
244+
type: "HISTOGRAM"
245+
unit: "ms"
246+
attributes:
247+
- name: "http.method"
248+
type: "STRING"
249+
- name: "http.status_code"
250+
type: "LONG"
251+
spans:
252+
- span_kind: "SERVER"
253+
attributes:
254+
- name: "http.method"
255+
type: "STRING"
256+
- name: "http.url"
257+
type: "STRING"
258+
- when: "otel.instrumentation.example.experimental-metrics.enabled" # Telemetry enabled by configuration
259+
metrics:
260+
- name: "example.experimental.metric"
261+
description: "Experimental metric enabled by configuration"
262+
type: "COUNTER"
263+
unit: "1"
264+
```
265+
266+
Each telemetry entry includes:
267+
268+
- `when`: The configuration condition under which this telemetry is emitted. Use `"default"` for telemetry
269+
emitted by default, or specify the configuration option name for conditional telemetry.
270+
- `metrics`: List of metrics with their name, description, type, unit, and attributes
271+
- `spans`: List of span configurations with their span_kind and attributes
272+
273+
For metrics, supported `type` values include: `COUNTER`, `GAUGE`, `HISTOGRAM`, `EXPONENTIAL_HISTOGRAM`.
274+
275+
For spans, supported `span_kind` values include: `CLIENT`, `SERVER`, `PRODUCER`, `CONSUMER`, `INTERNAL`.
276+
277+
For attributes, supported `type` values include: `STRING`, `LONG`, `DOUBLE`, `BOOLEAN`.
278+
279+
#### override_telemetry
280+
281+
Set `override_telemetry: true` to completely replace any auto-generated telemetry data from `.telemetry`
282+
files. When this is enabled, only the manually documented telemetry in `additional_telemetry` will be
283+
used, and any `.telemetry` files will be ignored.
284+
285+
```yaml
286+
override_telemetry: true
287+
additional_telemetry:
288+
- when: "default"
289+
metrics:
290+
- name: "manually.documented.metric"
291+
description: "This completely replaces auto-generated telemetry"
292+
type: "GAUGE"
293+
unit: "bytes"
294+
```
295+
296+
If `override_telemetry` is `false` or omitted (default behavior), manual telemetry will be merged with
297+
auto-generated telemetry, with manual entries taking precedence in case of conflicts (same metric name
298+
or span kind within the same `when` condition).
299+
208300
## Instrumentation List (docs/instrumentation-list.md)
209301

210302
The contents of the `metadata.yaml` files are combined with other information about the instrumentation

examples/distro/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ buildscript {
1212
}
1313
}
1414
dependencies {
15-
classpath "com.diffplug.spotless:spotless-plugin-gradle:7.2.1"
15+
classpath "com.diffplug.spotless:spotless-plugin-gradle:8.0.0"
1616
classpath "com.gradleup.shadow:shadow-gradle-plugin:9.2.1"
1717
classpath "io.opentelemetry.instrumentation:gradle-plugins:2.21.0-alpha-SNAPSHOT"
1818
}

examples/extension/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ plugins {
1111
See https://imperceptiblethoughts.com/shadow/ for more details about Shadow plugin.
1212
*/
1313
id "com.gradleup.shadow" version "9.2.1"
14-
id "com.diffplug.spotless" version "7.2.1"
14+
id "com.diffplug.spotless" version "8.0.0"
1515

1616
id "io.opentelemetry.instrumentation.muzzle-generation" version "2.21.0-alpha-SNAPSHOT"
1717
id "io.opentelemetry.instrumentation.muzzle-check" version "2.21.0-alpha-SNAPSHOT"

instrumentation-docs/instrumentations.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ readonly INSTRUMENTATIONS=(
1818
"apache-httpasyncclient-4.1:javaagent:test"
1919
"apache-httpclient:apache-httpclient-2.0:javaagent:test"
2020
"apache-httpclient:apache-httpclient-4.0:javaagent:test"
21-
"apache-httpclient:apache-httpclient-4.3:library:test"
21+
# "apache-httpclient:apache-httpclient-4.3:library:test" # See https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/14771
2222
"apache-httpclient:apache-httpclient-5.0:javaagent:test"
23-
"apache-httpclient:apache-httpclient-5.2:library:test"
23+
# "apache-httpclient:apache-httpclient-5.2:library:test" # See https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/14771
2424
"armeria:armeria-1.3:javaagent:test"
2525
"armeria:armeria-grpc-1.14:javaagent:test"
2626
"async-http-client:async-http-client-1.9:javaagent:test"

instrumentation-docs/readme.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,22 @@ configurations:
181181
description: Enables statement sanitization for database queries.
182182
type: boolean # boolean | string | list | map
183183
default: true
184+
override_telemetry: false # Set to true to ignore auto-generated .telemetry files
185+
additional_telemetry: # Manually document telemetry metadata
186+
- when: "default"
187+
metrics:
188+
- name: "metric.name"
189+
description: "Metric description"
190+
type: "COUNTER"
191+
unit: "1"
192+
attributes:
193+
- name: "attribute.name"
194+
type: "STRING"
195+
spans:
196+
- span_kind: "CLIENT"
197+
attributes:
198+
- name: "span.attribute"
199+
type: "STRING"
184200
```
185201

186202
### Gradle File Derived Information
@@ -214,6 +230,50 @@ data will be excluded from git and just generated on demand.
214230
Each file has a `when` value along with the list of metrics that indicates whether the telemetry is
215231
emitted by default or via a configuration option.
216232

233+
#### Manual Telemetry Documentation
234+
235+
In addition to auto-generated telemetry data from test runs, you can manually document telemetry
236+
metadata directly in the `metadata.yaml` file. This is useful for:
237+
238+
- Documenting telemetry that may not be captured during test runs
239+
- Overriding auto-generated telemetry data when it's incomplete or incorrect
240+
- Adding additional telemetry documentation that complements the auto-generated data
241+
242+
You can add manual telemetry documentation using the `additional_telemetry` field:
243+
244+
```yaml
245+
additional_telemetry:
246+
- when: "default" # or any configuration condition
247+
metrics:
248+
- name: "my.custom.metric"
249+
description: "Description of the metric"
250+
type: "COUNTER"
251+
unit: "1"
252+
attributes:
253+
- name: "attribute.name"
254+
type: "STRING"
255+
spans:
256+
- span_kind: "CLIENT"
257+
attributes:
258+
- name: "span.attribute"
259+
type: "STRING"
260+
```
261+
262+
To completely replace auto-generated telemetry data (ignoring `.telemetry` files), set `override_telemetry: true`:
263+
264+
```yaml
265+
override_telemetry: true
266+
additional_telemetry:
267+
- when: "default"
268+
metrics:
269+
- name: "documented.metric"
270+
description: "This replaces all auto-generated metrics"
271+
type: "GAUGE"
272+
unit: "ms"
273+
```
274+
275+
When both manual and auto-generated telemetry exist for the same `when` condition, they are merged with manual entries taking precedence in case of conflicts (same metric name or span kind).
276+
217277
## Doc Synchronization
218278

219279
The documentation site has a section that lists all the instrumentations in the context of

instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/InstrumentationAnalyzer.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
import com.fasterxml.jackson.core.JsonProcessingException;
99
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
1010
import com.fasterxml.jackson.databind.exc.ValueInstantiationException;
11+
import io.opentelemetry.instrumentation.docs.internal.EmittedMetrics;
12+
import io.opentelemetry.instrumentation.docs.internal.EmittedSpans;
1113
import io.opentelemetry.instrumentation.docs.internal.InstrumentationMetadata;
1214
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
1315
import io.opentelemetry.instrumentation.docs.internal.InstrumentationType;
16+
import io.opentelemetry.instrumentation.docs.internal.TelemetryMerger;
1417
import io.opentelemetry.instrumentation.docs.parsers.GradleParser;
1518
import io.opentelemetry.instrumentation.docs.parsers.MetricParser;
1619
import io.opentelemetry.instrumentation.docs.parsers.ModuleParser;
@@ -64,8 +67,9 @@ private void enrichModule(InstrumentationModule module) throws IOException {
6467
}
6568

6669
module.setTargetVersions(getVersionInformation(module));
67-
module.setMetrics(MetricParser.getMetrics(module, fileManager));
68-
module.setSpans(SpanParser.getSpans(module, fileManager));
70+
71+
// Handle telemetry merging (manual + emitted)
72+
setMergedTelemetry(module, metaData);
6973
}
7074

7175
@Nullable
@@ -88,4 +92,32 @@ private Map<InstrumentationType, Set<String>> getVersionInformation(
8892
List<String> gradleFiles = fileManager.findBuildGradleFiles(module.getSrcPath());
8993
return GradleParser.extractVersions(gradleFiles, module);
9094
}
95+
96+
/**
97+
* Sets merged telemetry data on the module, combining manual telemetry from metadata.yaml with
98+
* emitted telemetry from .telemetry files.
99+
*/
100+
private void setMergedTelemetry(
101+
InstrumentationModule module, @Nullable InstrumentationMetadata metadata) throws IOException {
102+
Map<String, List<EmittedMetrics.Metric>> emittedMetrics =
103+
MetricParser.getMetrics(module, fileManager);
104+
Map<String, List<EmittedSpans.Span>> emittedSpans = SpanParser.getSpans(module, fileManager);
105+
106+
if (metadata != null && !metadata.getAdditionalTelemetry().isEmpty()) {
107+
TelemetryMerger.MergedTelemetryData merged =
108+
TelemetryMerger.merge(
109+
metadata.getAdditionalTelemetry(),
110+
metadata.getOverrideTelemetry(),
111+
emittedMetrics,
112+
emittedSpans,
113+
module.getInstrumentationName());
114+
115+
module.setMetrics(merged.metrics());
116+
module.setSpans(merged.spans());
117+
} else {
118+
// No manual telemetry, use emitted only
119+
module.setMetrics(emittedMetrics);
120+
module.setSpans(emittedSpans);
121+
}
122+
}
91123
}

instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/internal/EmittedMetrics.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static java.util.Collections.emptyList;
99

1010
import com.fasterxml.jackson.annotation.JsonProperty;
11+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1112
import java.util.ArrayList;
1213
import java.util.List;
1314

@@ -157,5 +158,55 @@ public List<TelemetryAttribute> getAttributes() {
157158
public void setAttributes(List<TelemetryAttribute> attributes) {
158159
this.attributes = attributes;
159160
}
161+
162+
/**
163+
* Builder for creating EmittedMetrics.Metric instances. This class is internal and is hence not
164+
* for public use. Its APIs are unstable and can change at any time.
165+
*/
166+
public static class Builder {
167+
private String name = "";
168+
private String description = "";
169+
private String type = "";
170+
private String unit = "";
171+
private List<TelemetryAttribute> attributes = new ArrayList<>();
172+
173+
@CanIgnoreReturnValue
174+
public Builder name(String name) {
175+
this.name = name;
176+
return this;
177+
}
178+
179+
@CanIgnoreReturnValue
180+
public Builder description(String description) {
181+
this.description = description;
182+
return this;
183+
}
184+
185+
@CanIgnoreReturnValue
186+
public Builder type(String type) {
187+
this.type = type;
188+
return this;
189+
}
190+
191+
@CanIgnoreReturnValue
192+
public Builder unit(String unit) {
193+
this.unit = unit;
194+
return this;
195+
}
196+
197+
@CanIgnoreReturnValue
198+
public Builder attributes(List<TelemetryAttribute> attributes) {
199+
this.attributes = attributes != null ? attributes : new ArrayList<>();
200+
return this;
201+
}
202+
203+
public Metric build() {
204+
return new Metric(name, description, type, unit, attributes);
205+
}
206+
}
207+
208+
public static Builder builder() {
209+
return new Builder();
210+
}
160211
}
161212
}

0 commit comments

Comments
 (0)