Skip to content

Commit 7d796ab

Browse files
jaydelucalaurit
andauthored
Add ability to document configuration options in metadata.yaml (#13742)
Co-authored-by: Lauri Tulmin <[email protected]>
1 parent 0d9aa37 commit 7d796ab

File tree

15 files changed

+295
-25
lines changed

15 files changed

+295
-25
lines changed

docs/instrumentation-list.yaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,21 @@ libraries:
239239
- org.apache.camel:camel-core:[2.19,3)
240240
cassandra:
241241
- name: cassandra-4.0
242+
description: |
243+
Instruments the Cassandra database client, providing database client spans and metrics for Cassandra queries.
242244
source_path: instrumentation/cassandra/cassandra-4.0
243245
scope:
244246
name: io.opentelemetry.cassandra-4.0
245247
target_versions:
246248
javaagent:
247249
- com.datastax.oss:java-driver-core:[4.0,4.4)
250+
configurations:
251+
- name: otel.instrumentation.common.db-statement-sanitizer.enabled
252+
description: Enables statement sanitization for database queries.
253+
default: 'true'
248254
- name: cassandra-4.4
255+
description: |
256+
Instruments the Cassandra database client, providing database client spans and metrics for Cassandra queries.
249257
source_path: instrumentation/cassandra/cassandra-4.4
250258
scope:
251259
name: io.opentelemetry.cassandra-4.4
@@ -254,13 +262,23 @@ libraries:
254262
- com.datastax.oss:java-driver-core:[4.4,]
255263
library:
256264
- com.datastax.oss:java-driver-core:4.4.0
265+
configurations:
266+
- name: otel.instrumentation.common.db-statement-sanitizer.enabled
267+
description: Enables statement sanitization for database queries.
268+
default: 'true'
257269
- name: cassandra-3.0
270+
description: |
271+
Instruments the Cassandra database client, providing database client spans and metrics for Cassandra queries.
258272
source_path: instrumentation/cassandra/cassandra-3.0
259273
scope:
260274
name: io.opentelemetry.cassandra-3.0
261275
target_versions:
262276
javaagent:
263277
- com.datastax.cassandra:cassandra-driver-core:[3.0,4.0)
278+
configurations:
279+
- name: otel.instrumentation.common.db-statement-sanitizer.enabled
280+
description: Enables statement sanitization for database queries.
281+
default: 'true'
264282
clickhouse:
265283
- name: clickhouse-client-0.5
266284
description: Instruments the V1 ClickHouseClient, providing database client spans
@@ -271,6 +289,10 @@ libraries:
271289
target_versions:
272290
javaagent:
273291
- com.clickhouse.client:clickhouse-client:[0.5.0,)
292+
configurations:
293+
- name: otel.instrumentation.common.db-statement-sanitizer.enabled
294+
description: Enables statement sanitization for database queries.
295+
default: 'true'
274296
couchbase:
275297
- name: couchbase-3.1.6
276298
source_path: instrumentation/couchbase/couchbase-3.1.6
@@ -382,12 +404,21 @@ libraries:
382404
- org.elasticsearch:elasticsearch:[5.3.0,6.0.0)
383405
executors:
384406
- name: executors
407+
description: |
408+
The executor instrumentation ensures that context is automatically propagated when using common Java executors (e.g., ThreadPoolExecutor, ScheduledThreadPoolExecutor, ForkJoinPool). When a task is submitted, the current context is captured and bound to the task. Then, when the task eventually runs, even if it’s on a different thread, the instrumentation reactivates that context, enabling consistent correlation across concurrent and asynchronous workflows.
385409
source_path: instrumentation/executors
386410
scope:
387411
name: io.opentelemetry.executors
388412
target_versions:
389413
javaagent:
390414
- Java 8+
415+
configurations:
416+
- name: otel.instrumentation.executors.include
417+
description: List of Executor subclasses to be instrumented.
418+
default: ''
419+
- name: otel.instrumentation.executors.include-all
420+
description: Whether to instrument all classes that implement the Executor interface.
421+
default: 'false'
391422
finagle:
392423
- name: finagle-http-23.11
393424
source_path: instrumentation/finagle-http-23.11
@@ -708,13 +739,27 @@ libraries:
708739
- org.jboss.logmanager:jboss-logmanager:[1.1.0.GA,)
709740
jdbc:
710741
- name: jdbc
742+
description: |
743+
The JDBC instrumentation provides database client spans and metrics. Each call produces a span named after the SQL verb, enriched with standard DB client attributes (system, database, operation, sanitized statement, peer address) and error details if an exception occurs.
711744
disabled_by_default: true
712745
source_path: instrumentation/jdbc
713746
scope:
714747
name: io.opentelemetry.jdbc
715748
target_versions:
716749
javaagent:
717750
- Java 8+
751+
configurations:
752+
- name: otel.instrumentation.jdbc.statement-sanitizer.enabled
753+
description: Enables statement sanitization for database queries. Takes precedent
754+
to otel.instrumentation.common.db-statement-sanitizer.enabled.
755+
default: 'true'
756+
- name: otel.instrumentation.common.db-statement-sanitizer.enabled
757+
description: Enables statement sanitization for database queries.
758+
default: 'true'
759+
- name: otel.instrumentation.common.peer-service-mapping
760+
description: Used to specify a mapping from host names or IP addresses to peer
761+
services.
762+
default: ''
718763
jedis:
719764
- name: jedis-1.4
720765
source_path: instrumentation/jedis/jedis-1.4

instrumentation-docs/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ otelJava {
88

99
dependencies {
1010
implementation("org.yaml:snakeyaml:2.4")
11+
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.2")
1112
implementation("io.opentelemetry:opentelemetry-sdk-common")
1213

1314
testImplementation(enforcedPlatform("org.junit:junit-bom:5.12.2"))

instrumentation-docs/readme.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ public class SpringWebInstrumentationModule extends InstrumentationModule
6767
* List of supported versions by the module, broken down by `library` or `javaagent` support
6868
* scope
6969
* Name: The scope name of the instrumentation, `io.opentelemetry.{instrumentation name}`
70+
* configurations settings
71+
* List of settings that are available for the instrumentation module
72+
* Each setting has a name, description, and default value
7073

7174
## Methodology
7275

@@ -81,6 +84,10 @@ As of now, the following fields are supported, all of which are optional:
8184
description: "Instruments..." # Description of the instrumentation module
8285
disabled_by_default: true # Defaults to `false`
8386
classification: internal # instrumentation classification: library | internal | custom
87+
configurations:
88+
- name: otel.instrumentation.common.db-statement-sanitizer.enabled
89+
description: Enables statement sanitization for database queries.
90+
default: true
8491
```
8592

8693
### Gradle File Derived Information

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

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
package io.opentelemetry.instrumentation.docs;
77

8+
import static java.util.Locale.Category.FORMAT;
9+
10+
import com.fasterxml.jackson.core.JsonProcessingException;
811
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
912
import io.opentelemetry.instrumentation.docs.utils.FileManager;
1013
import io.opentelemetry.instrumentation.docs.utils.YamlHelper;
@@ -14,13 +17,16 @@
1417
import java.nio.file.Files;
1518
import java.nio.file.Paths;
1619
import java.util.List;
20+
import java.util.Locale;
21+
import java.util.TreeMap;
1722
import java.util.logging.Logger;
23+
import java.util.stream.Collectors;
1824

1925
public class DocGeneratorApplication {
2026

2127
private static final Logger logger = Logger.getLogger(DocGeneratorApplication.class.getName());
2228

23-
public static void main(String[] args) {
29+
public static void main(String[] args) throws JsonProcessingException {
2430
FileManager fileManager = new FileManager("instrumentation/");
2531
List<InstrumentationModule> modules = new InstrumentationAnalyzer(fileManager).analyze();
2632

@@ -35,6 +41,67 @@ public static void main(String[] args) {
3541
} catch (IOException e) {
3642
logger.severe("Error writing instrumentation list: " + e.getMessage());
3743
}
44+
45+
printStats(modules);
46+
}
47+
48+
private static void printStats(List<InstrumentationModule> modules) {
49+
List<InstrumentationModule> metadata =
50+
modules.stream().filter(m -> m.getMetadata() != null).toList();
51+
52+
long withDescriptions =
53+
metadata.stream()
54+
.filter(
55+
m ->
56+
m.getMetadata().getDescription() != null
57+
&& !m.getMetadata().getDescription().isEmpty())
58+
.count();
59+
60+
long withConfigurations =
61+
metadata.stream().filter(m -> !m.getMetadata().getConfigurations().isEmpty()).count();
62+
63+
String stats =
64+
String.format(
65+
Locale.getDefault(FORMAT),
66+
"""
67+
-----------------------------------
68+
Analysis Summary:
69+
Total Modules: %d
70+
By classification:
71+
%s
72+
metadata.yaml contents:
73+
%s
74+
%s
75+
""",
76+
modules.size(),
77+
getClassificationStats(modules),
78+
getPercentage("descriptions", withDescriptions, modules.size()),
79+
getPercentage("configurations", withConfigurations, modules.size()));
80+
81+
logger.info(stats);
82+
}
83+
84+
private static String getClassificationStats(List<InstrumentationModule> modules) {
85+
return modules.stream()
86+
.collect(
87+
Collectors.groupingBy(
88+
m -> m.getMetadata().getClassification(), TreeMap::new, Collectors.toList()))
89+
.entrySet()
90+
.stream()
91+
.map(
92+
entry ->
93+
String.format(
94+
Locale.getDefault(FORMAT), "\t%s: %d", entry.getKey(), entry.getValue().size()))
95+
.collect(Collectors.joining("\n"));
96+
}
97+
98+
private static String getPercentage(String label, long numerator, long denominator) {
99+
return label
100+
+ ": "
101+
+ numerator
102+
+ " ("
103+
+ String.format(Locale.getDefault(FORMAT), "%.2f", (double) numerator / denominator * 100)
104+
+ "%)";
38105
}
39106

40107
private DocGeneratorApplication() {}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import static io.opentelemetry.instrumentation.docs.parsers.GradleParser.parseGradleFile;
99

10+
import com.fasterxml.jackson.core.JsonProcessingException;
1011
import io.opentelemetry.instrumentation.docs.internal.DependencyInfo;
1112
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
1213
import io.opentelemetry.instrumentation.docs.internal.InstrumentationType;
@@ -62,7 +63,7 @@ public static List<InstrumentationModule> convertToInstrumentationModules(
6263
*
6364
* @return a list of {@link InstrumentationModule}
6465
*/
65-
List<InstrumentationModule> analyze() {
66+
List<InstrumentationModule> analyze() throws JsonProcessingException {
6667
List<InstrumentationPath> paths = fileManager.getInstrumentationPaths();
6768
List<InstrumentationModule> modules = convertToInstrumentationModules(paths);
6869

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.docs.internal;
7+
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
10+
/**
11+
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
12+
* any time.
13+
*/
14+
public record ConfigurationOption(
15+
String name, String description, @JsonProperty("default") String defaultValue) {}

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
package io.opentelemetry.instrumentation.docs.internal;
77

8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
import java.util.Collections;
10+
import java.util.List;
811
import java.util.Objects;
912
import javax.annotation.Nonnull;
1013
import javax.annotation.Nullable;
@@ -15,16 +18,26 @@
1518
*/
1619
public class InstrumentationMetaData {
1720
@Nullable private String description;
18-
@Nullable private Boolean disabledByDefault;
21+
22+
@JsonProperty("disabled_by_default")
23+
@Nullable
24+
private Boolean disabledByDefault;
25+
1926
private String classification;
2027

28+
private List<ConfigurationOption> configurations = Collections.emptyList();
29+
2130
public InstrumentationMetaData() {}
2231

2332
public InstrumentationMetaData(
24-
String description, String classification, Boolean disabledByDefault) {
33+
String description,
34+
String classification,
35+
Boolean disabledByDefault,
36+
List<ConfigurationOption> configurations) {
2537
this.classification = classification;
2638
this.disabledByDefault = disabledByDefault;
2739
this.description = description;
40+
this.configurations = Objects.requireNonNullElse(configurations, Collections.emptyList());
2841
}
2942

3043
@Nullable
@@ -54,4 +67,12 @@ public void setClassification(@Nullable String classification) {
5467
public void setDisabledByDefault(@Nullable Boolean disabledByDefault) {
5568
this.disabledByDefault = disabledByDefault;
5669
}
70+
71+
public List<ConfigurationOption> getConfigurations() {
72+
return configurations;
73+
}
74+
75+
public void setConfigurations(@Nullable List<ConfigurationOption> configurations) {
76+
this.configurations = Objects.requireNonNullElse(configurations, Collections.emptyList());
77+
}
5778
}

instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/utils/YamlHelper.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
package io.opentelemetry.instrumentation.docs.utils;
77

8+
import com.fasterxml.jackson.core.JsonProcessingException;
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
11+
import io.opentelemetry.instrumentation.docs.internal.ConfigurationOption;
812
import io.opentelemetry.instrumentation.docs.internal.InstrumentationClassification;
913
import io.opentelemetry.instrumentation.docs.internal.InstrumentationMetaData;
1014
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
@@ -17,23 +21,13 @@
1721
import java.util.logging.Logger;
1822
import java.util.stream.Collectors;
1923
import org.yaml.snakeyaml.DumperOptions;
20-
import org.yaml.snakeyaml.TypeDescription;
2124
import org.yaml.snakeyaml.Yaml;
2225

2326
public class YamlHelper {
2427

2528
private static final Logger logger = Logger.getLogger(YamlHelper.class.getName());
2629

27-
private static final Yaml metaDataYaml = new Yaml();
28-
29-
static {
30-
TypeDescription customDescriptor = new TypeDescription(InstrumentationMetaData.class);
31-
customDescriptor.substituteProperty(
32-
"disabled_by_default", Boolean.class, "getDisabledByDefault", "setDisabledByDefault");
33-
customDescriptor.substituteProperty(
34-
"classification", String.class, "getClassification", "setClassification");
35-
metaDataYaml.addTypeDescription(customDescriptor);
36-
}
30+
private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
3731

3832
public static void generateInstrumentationYaml(
3933
List<InstrumentationModule> list, BufferedWriter writer) {
@@ -149,6 +143,18 @@ private static Map<String, Object> baseProperties(InstrumentationModule module)
149143
moduleMap.put("target_versions", targetVersions);
150144
}
151145

146+
if (module.getMetadata() != null && !module.getMetadata().getConfigurations().isEmpty()) {
147+
List<Map<String, String>> configurations = new ArrayList<>();
148+
for (ConfigurationOption configuration : module.getMetadata().getConfigurations()) {
149+
Map<String, String> conf = new LinkedHashMap<>();
150+
conf.put("name", configuration.name());
151+
conf.put("description", configuration.description());
152+
conf.put("default", configuration.defaultValue());
153+
configurations.add(conf);
154+
}
155+
moduleMap.put("configurations", configurations);
156+
}
157+
152158
return moduleMap;
153159
}
154160

@@ -158,8 +164,9 @@ private static Map<String, Object> getScopeMap(InstrumentationModule module) {
158164
return scopeMap;
159165
}
160166

161-
public static InstrumentationMetaData metaDataParser(String input) {
162-
return metaDataYaml.loadAs(input, InstrumentationMetaData.class);
167+
public static InstrumentationMetaData metaDataParser(String input)
168+
throws JsonProcessingException {
169+
return mapper.readValue(input, InstrumentationMetaData.class);
163170
}
164171

165172
private YamlHelper() {}

0 commit comments

Comments
 (0)