Skip to content

Commit 3f25f84

Browse files
committed
Add scope schema url to metadata
1 parent 561042d commit 3f25f84

File tree

11 files changed

+620
-5
lines changed

11 files changed

+620
-5
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
1515
import io.opentelemetry.instrumentation.docs.internal.InstrumentationType;
1616
import io.opentelemetry.instrumentation.docs.internal.TelemetryMerger;
17+
import io.opentelemetry.instrumentation.docs.parsers.EmittedScopeParser;
1718
import io.opentelemetry.instrumentation.docs.parsers.GradleParser;
1819
import io.opentelemetry.instrumentation.docs.parsers.MetricParser;
1920
import io.opentelemetry.instrumentation.docs.parsers.ModuleParser;
2021
import io.opentelemetry.instrumentation.docs.parsers.SpanParser;
2122
import io.opentelemetry.instrumentation.docs.utils.FileManager;
2223
import io.opentelemetry.instrumentation.docs.utils.InstrumentationPath;
2324
import io.opentelemetry.instrumentation.docs.utils.YamlHelper;
25+
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
2426
import java.io.IOException;
2527
import java.util.List;
2628
import java.util.Map;
@@ -70,6 +72,11 @@ private void enrichModule(InstrumentationModule module) throws IOException {
7072

7173
// Handle telemetry merging (manual + emitted)
7274
setMergedTelemetry(module, metaData);
75+
76+
InstrumentationScopeInfo scopeInfo = EmittedScopeParser.getScope(fileManager, module);
77+
if (scopeInfo != null) {
78+
module.setScopeInfo(scopeInfo);
79+
}
7380
}
7481

7582
@Nullable
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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 io.opentelemetry.api.common.Attributes;
9+
import java.util.List;
10+
import java.util.Objects;
11+
import javax.annotation.Nullable;
12+
13+
/**
14+
* Representation of Scopes emitted the tests in a module. This class is internal and is hence not
15+
* for public use. Its APIs are unstable and can change at any time.
16+
*/
17+
public class EmittedScope {
18+
@Nullable private List<Scope> scopes;
19+
20+
public EmittedScope() {}
21+
22+
public EmittedScope(List<Scope> scopes) {
23+
this.scopes = scopes;
24+
}
25+
26+
@Nullable
27+
public List<Scope> getScopes() {
28+
return scopes;
29+
}
30+
31+
public void setScopes(List<Scope> scopes) {
32+
this.scopes = scopes;
33+
}
34+
35+
/**
36+
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
37+
* any time.
38+
*/
39+
public static class Scope {
40+
@Nullable private String name;
41+
@Nullable private String version;
42+
@Nullable private String schemaUrl;
43+
@Nullable private Attributes attributes;
44+
45+
public Scope() {}
46+
47+
public Scope(String name, String version, String schemaUrl, Attributes attributes) {
48+
this.name = name;
49+
this.version = version;
50+
this.schemaUrl = schemaUrl;
51+
this.attributes = attributes;
52+
}
53+
54+
@Nullable
55+
public String getName() {
56+
return name;
57+
}
58+
59+
public void setName(String name) {
60+
this.name = name;
61+
}
62+
63+
@Nullable
64+
public String getVersion() {
65+
return version;
66+
}
67+
68+
public void setVersion(String version) {
69+
this.version = version;
70+
}
71+
72+
@Nullable
73+
public String getSchemaUrl() {
74+
return schemaUrl;
75+
}
76+
77+
public void setSchemaUrl(String schemaUrl) {
78+
this.schemaUrl = schemaUrl;
79+
}
80+
81+
@Nullable
82+
public Attributes getAttributes() {
83+
return attributes;
84+
}
85+
86+
public void setAttributes(Attributes attributes) {
87+
this.attributes = attributes;
88+
}
89+
90+
@Override
91+
public boolean equals(Object o) {
92+
if (this == o) {
93+
return true;
94+
}
95+
if (!(o instanceof Scope scope)) {
96+
return false;
97+
}
98+
99+
if (!Objects.equals(name, scope.name)) {
100+
return false;
101+
}
102+
if (!Objects.equals(version, scope.version)) {
103+
return false;
104+
}
105+
return Objects.equals(schemaUrl, scope.schemaUrl);
106+
}
107+
108+
@Override
109+
public int hashCode() {
110+
int result = name != null ? name.hashCode() : 0;
111+
result = 31 * result + (version != null ? version.hashCode() : 0);
112+
result = 31 * result + (schemaUrl != null ? schemaUrl.hashCode() : 0);
113+
return result;
114+
}
115+
}
116+
}

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class InstrumentationModule {
2727
private final String instrumentationName;
2828
private final String namespace;
2929
private final String group;
30-
private final InstrumentationScopeInfo scopeInfo;
30+
private InstrumentationScopeInfo scopeInfo;
3131
private Map<String, List<EmittedMetrics.Metric>> metrics;
3232
private Map<String, List<EmittedSpans.Span>> spans;
3333

@@ -56,7 +56,10 @@ public InstrumentationModule(Builder builder) {
5656
this.metadata = builder.metadata;
5757
this.targetVersions = builder.targetVersions;
5858
this.minJavaVersion = builder.minJavaVersion;
59-
this.scopeInfo = InstrumentationScopeInfo.create("io.opentelemetry." + instrumentationName);
59+
this.scopeInfo =
60+
Objects.requireNonNullElseGet(
61+
builder.scopeInfo,
62+
() -> InstrumentationScopeInfo.create("io.opentelemetry." + instrumentationName));
6063
}
6164

6265
public String getSrcPath() {
@@ -109,6 +112,10 @@ public void setTargetVersions(Map<InstrumentationType, Set<String>> targetVersio
109112
this.targetVersions = targetVersions;
110113
}
111114

115+
public void setScopeInfo(InstrumentationScopeInfo scopeInfo) {
116+
this.scopeInfo = scopeInfo;
117+
}
118+
112119
public void setMetadata(InstrumentationMetadata metadata) {
113120
this.metadata = metadata;
114121
}
@@ -136,6 +143,7 @@ public static class Builder {
136143
@Nullable private String group;
137144
@Nullable private Integer minJavaVersion;
138145
@Nullable private InstrumentationMetadata metadata;
146+
@Nullable private InstrumentationScopeInfo scopeInfo;
139147
@Nullable private Map<InstrumentationType, Set<String>> targetVersions;
140148
@Nullable private Map<String, List<EmittedMetrics.Metric>> metrics;
141149
@Nullable private Map<String, List<EmittedSpans.Span>> spans;
@@ -158,6 +166,12 @@ public Builder namespace(String namespace) {
158166
return this;
159167
}
160168

169+
@CanIgnoreReturnValue
170+
public Builder scope(InstrumentationScopeInfo scope) {
171+
this.scopeInfo = scope;
172+
return this;
173+
}
174+
161175
@CanIgnoreReturnValue
162176
public Builder minJavaVersion(Integer minJavaVersion) {
163177
this.minJavaVersion = minJavaVersion;
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.docs.parsers;
7+
8+
import io.opentelemetry.instrumentation.docs.internal.EmittedScope;
9+
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
10+
import io.opentelemetry.instrumentation.docs.utils.FileManager;
11+
import io.opentelemetry.instrumentation.docs.utils.YamlHelper;
12+
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
13+
import io.opentelemetry.sdk.common.InstrumentationScopeInfoBuilder;
14+
import java.io.IOException;
15+
import java.nio.file.Files;
16+
import java.nio.file.Path;
17+
import java.nio.file.Paths;
18+
import java.util.HashSet;
19+
import java.util.List;
20+
import java.util.Set;
21+
import java.util.logging.Logger;
22+
import java.util.stream.Stream;
23+
import javax.annotation.Nullable;
24+
25+
/**
26+
* This class is responsible for parsing scope files from the `.telemetry` directory of an
27+
* instrumentation module and collecting all unique scopes.
28+
*/
29+
public class EmittedScopeParser {
30+
private static final Logger logger = Logger.getLogger(EmittedScopeParser.class.getName());
31+
32+
@Nullable
33+
public static InstrumentationScopeInfo getScope(
34+
FileManager fileManager, InstrumentationModule module) {
35+
Set<EmittedScope.Scope> scopes =
36+
EmittedScopeParser.getScopesFromFiles(fileManager.rootDir(), module.getSrcPath());
37+
if (scopes.isEmpty()) {
38+
return null;
39+
}
40+
41+
EmittedScope.Scope scope =
42+
scopes.stream()
43+
.filter(
44+
item ->
45+
item.getName() != null
46+
&& item.getName().contains(module.getInstrumentationName()))
47+
.findFirst()
48+
.orElse(null);
49+
if (scope == null) {
50+
return null;
51+
}
52+
53+
String instrumentationName = "io.opentelemetry." + module.getInstrumentationName();
54+
InstrumentationScopeInfoBuilder builder = InstrumentationScopeInfo.builder(instrumentationName);
55+
56+
// This will identify any module that might deviate from the standard naming convention
57+
if (scope.getName() != null && !scope.getName().equals(instrumentationName)) {
58+
logger.severe(
59+
"Scope name mismatch. Expected: " + instrumentationName + ", got: " + scope.getName());
60+
}
61+
62+
if (scope.getSchemaUrl() != null) {
63+
builder.setSchemaUrl(scope.getSchemaUrl());
64+
}
65+
if (scope.getAttributes() != null) {
66+
builder.setAttributes(scope.getAttributes());
67+
}
68+
69+
return builder.build();
70+
}
71+
72+
/**
73+
* Looks for scope files in the .telemetry directory and collects all unique scopes.
74+
*
75+
* @param rootDir the root directory
76+
* @param instrumentationDirectory the instrumentation directory relative to root
77+
* @return set of all unique scopes found in scope files
78+
*/
79+
public static Set<EmittedScope.Scope> getScopesFromFiles(
80+
String rootDir, String instrumentationDirectory) {
81+
Path telemetryDir = Paths.get(rootDir + "/" + instrumentationDirectory, ".telemetry");
82+
83+
return parseAllScopeFiles(telemetryDir);
84+
}
85+
86+
/**
87+
* Parses all scope-*.yaml files in the .telemetry directory and collects all unique scopes.
88+
*
89+
* @param telemetryDir the path to the .telemetry directory
90+
* @return a set of unique scopes
91+
*/
92+
private static Set<EmittedScope.Scope> parseAllScopeFiles(Path telemetryDir) {
93+
Set<EmittedScope.Scope> allScopes = new HashSet<>();
94+
95+
if (Files.exists(telemetryDir) && Files.isDirectory(telemetryDir)) {
96+
try (Stream<Path> files = Files.list(telemetryDir)) {
97+
files
98+
.filter(path -> path.getFileName().toString().startsWith("scope-"))
99+
.forEach(
100+
path -> {
101+
String content = FileManager.readFileToString(path.toString());
102+
if (content != null) {
103+
EmittedScope parsed;
104+
try {
105+
parsed = YamlHelper.emittedScopeParser(content);
106+
} catch (RuntimeException e) {
107+
logger.severe("Error parsing scope file (" + path + "): " + e.getMessage());
108+
return;
109+
}
110+
111+
List<EmittedScope.Scope> scopes = parsed.getScopes();
112+
if (scopes != null) {
113+
allScopes.addAll(scopes);
114+
}
115+
}
116+
});
117+
} catch (IOException e) {
118+
logger.severe("Error reading scope files: " + e.getMessage());
119+
}
120+
}
121+
return allScopes;
122+
}
123+
124+
private EmittedScopeParser() {}
125+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.opentelemetry.instrumentation.docs.internal.ConfigurationOption;
1212
import io.opentelemetry.instrumentation.docs.internal.ConfigurationType;
1313
import io.opentelemetry.instrumentation.docs.internal.EmittedMetrics;
14+
import io.opentelemetry.instrumentation.docs.internal.EmittedScope;
1415
import io.opentelemetry.instrumentation.docs.internal.EmittedSpans;
1516
import io.opentelemetry.instrumentation.docs.internal.InstrumentationClassification;
1617
import io.opentelemetry.instrumentation.docs.internal.InstrumentationMetadata;
@@ -228,6 +229,9 @@ private static void addMetadataProperties(
228229
private static Map<String, Object> getScopeMap(InstrumentationModule module) {
229230
Map<String, Object> scopeMap = new LinkedHashMap<>();
230231
scopeMap.put("name", module.getScopeInfo().getName());
232+
if (module.getScopeInfo().getSchemaUrl() != null) {
233+
scopeMap.put("schema_url", module.getScopeInfo().getSchemaUrl());
234+
}
231235
return scopeMap;
232236
}
233237

@@ -313,6 +317,10 @@ public static InstrumentationMetadata metaDataParser(String input)
313317
return mapper.readValue(input, InstrumentationMetadata.class);
314318
}
315319

320+
public static EmittedScope emittedScopeParser(String input) {
321+
return new Yaml().loadAs(input, EmittedScope.class);
322+
}
323+
316324
public static EmittedMetrics emittedMetricsParser(String input) throws JsonProcessingException {
317325
return mapper.readValue(input, EmittedMetrics.class);
318326
}

0 commit comments

Comments
 (0)