Skip to content

Commit 4256d18

Browse files
committed
attributes
1 parent 3f25f84 commit 4256d18

File tree

6 files changed

+223
-23
lines changed

6 files changed

+223
-23
lines changed

instrumentation-docs/readme.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,12 @@ public class SpringWebInstrumentationModule extends InstrumentationModule
155155
* Short description of what the instrumentation does
156156
* target_versions
157157
* List of supported versions by the module, broken down by `library` or `javaagent` support
158-
* scope
159-
* Name: The scope name of the instrumentation, `io.opentelemetry.{instrumentation name}`
158+
* scope (https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/)
159+
* name: The scope name of the instrumentation, `io.opentelemetry.{instrumentation name}`
160+
* schema_url: Location of the telemetry schema that the instrumentation’s emitted telemetry
161+
conforms to. See https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
162+
* attributes: The instrumentation scope’s optional attributes provide additional information
163+
about the scope.
160164
* configuration settings
161165
* List of settings that are available for the instrumentation module
162166
* Each setting has a name, description, type, and default value

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

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

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

8-
import io.opentelemetry.api.common.Attributes;
98
import java.util.List;
9+
import java.util.Map;
1010
import java.util.Objects;
1111
import javax.annotation.Nullable;
1212

@@ -40,11 +40,11 @@ public static class Scope {
4040
@Nullable private String name;
4141
@Nullable private String version;
4242
@Nullable private String schemaUrl;
43-
@Nullable private Attributes attributes;
43+
@Nullable private Map<String, Object> attributes;
4444

4545
public Scope() {}
4646

47-
public Scope(String name, String version, String schemaUrl, Attributes attributes) {
47+
public Scope(String name, String version, String schemaUrl, Map<String, Object> attributes) {
4848
this.name = name;
4949
this.version = version;
5050
this.schemaUrl = schemaUrl;
@@ -79,11 +79,11 @@ public void setSchemaUrl(String schemaUrl) {
7979
}
8080

8181
@Nullable
82-
public Attributes getAttributes() {
82+
public Map<String, Object> getAttributes() {
8383
return attributes;
8484
}
8585

86-
public void setAttributes(Attributes attributes) {
86+
public void setAttributes(Map<String, Object> attributes) {
8787
this.attributes = attributes;
8888
}
8989

@@ -102,15 +102,15 @@ public boolean equals(Object o) {
102102
if (!Objects.equals(version, scope.version)) {
103103
return false;
104104
}
105-
return Objects.equals(schemaUrl, scope.schemaUrl);
105+
if (!Objects.equals(schemaUrl, scope.schemaUrl)) {
106+
return false;
107+
}
108+
return Objects.equals(attributes, scope.attributes);
106109
}
107110

108111
@Override
109112
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;
113+
return Objects.hash(name, version, schemaUrl, attributes);
114114
}
115115
}
116116
}

instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/parsers/EmittedScopeParser.java

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

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

8+
import static io.opentelemetry.api.common.AttributeKey.booleanKey;
9+
import static io.opentelemetry.api.common.AttributeKey.doubleKey;
10+
import static io.opentelemetry.api.common.AttributeKey.longKey;
11+
import static io.opentelemetry.api.common.AttributeKey.stringKey;
12+
13+
import io.opentelemetry.api.common.Attributes;
14+
import io.opentelemetry.api.common.AttributesBuilder;
815
import io.opentelemetry.instrumentation.docs.internal.EmittedScope;
916
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
1017
import io.opentelemetry.instrumentation.docs.utils.FileManager;
@@ -17,6 +24,7 @@
1724
import java.nio.file.Paths;
1825
import java.util.HashSet;
1926
import java.util.List;
27+
import java.util.Map;
2028
import java.util.Set;
2129
import java.util.logging.Logger;
2230
import java.util.stream.Stream;
@@ -63,12 +71,40 @@ public static InstrumentationScopeInfo getScope(
6371
builder.setSchemaUrl(scope.getSchemaUrl());
6472
}
6573
if (scope.getAttributes() != null) {
66-
builder.setAttributes(scope.getAttributes());
74+
builder.setAttributes(convertMapToAttributes(scope.getAttributes()));
6775
}
6876

6977
return builder.build();
7078
}
7179

80+
/**
81+
* Converts a {@code Map<String, Object>} to Attributes.
82+
*
83+
* @param attributeMap the map of attributes from YAML
84+
* @return Attributes
85+
*/
86+
private static Attributes convertMapToAttributes(Map<String, Object> attributeMap) {
87+
AttributesBuilder builder = Attributes.builder();
88+
for (Map.Entry<String, Object> entry : attributeMap.entrySet()) {
89+
Object value = entry.getValue();
90+
if (value instanceof String string) {
91+
builder.put(stringKey(entry.getKey()), string);
92+
} else if (value instanceof Long longValue) {
93+
builder.put(longKey(entry.getKey()), longValue);
94+
} else if (value instanceof Integer intValue) {
95+
builder.put(longKey(entry.getKey()), intValue.longValue());
96+
} else if (value instanceof Double doubleValue) {
97+
builder.put(doubleKey(entry.getKey()), doubleValue);
98+
} else if (value instanceof Boolean boolValue) {
99+
builder.put(booleanKey(entry.getKey()), boolValue);
100+
} else {
101+
// Fallback to string representation for unknown types
102+
builder.put(stringKey(entry.getKey()), String.valueOf(value));
103+
}
104+
}
105+
return builder.build();
106+
}
107+
72108
/**
73109
* Looks for scope files in the .telemetry directory and collects all unique scopes.
74110
*
@@ -80,16 +116,6 @@ public static Set<EmittedScope.Scope> getScopesFromFiles(
80116
String rootDir, String instrumentationDirectory) {
81117
Path telemetryDir = Paths.get(rootDir + "/" + instrumentationDirectory, ".telemetry");
82118

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) {
93119
Set<EmittedScope.Scope> allScopes = new HashSet<>();
94120

95121
if (Files.exists(telemetryDir) && Files.isDirectory(telemetryDir)) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,15 @@ private static Map<String, Object> getScopeMap(InstrumentationModule module) {
232232
if (module.getScopeInfo().getSchemaUrl() != null) {
233233
scopeMap.put("schema_url", module.getScopeInfo().getSchemaUrl());
234234
}
235+
if (module.getScopeInfo().getAttributes() != null
236+
&& !module.getScopeInfo().getAttributes().isEmpty()) {
237+
Map<String, Object> attributesMap = new LinkedHashMap<>();
238+
module
239+
.getScopeInfo()
240+
.getAttributes()
241+
.forEach((key, value) -> attributesMap.put(key.getKey(), value));
242+
scopeMap.put("attributes", attributesMap);
243+
}
235244
return scopeMap;
236245
}
237246

instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/parsers/EmittedScopeParserTest.java

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

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

8+
import static io.opentelemetry.api.common.AttributeKey.stringKey;
89
import static org.assertj.core.api.Assertions.assertThat;
910

11+
import io.opentelemetry.api.common.AttributeKey;
1012
import io.opentelemetry.instrumentation.docs.internal.EmittedScope;
1113
import io.opentelemetry.instrumentation.docs.internal.InstrumentationModule;
1214
import io.opentelemetry.instrumentation.docs.utils.FileManager;
@@ -284,4 +286,154 @@ void testGetScopeMultipleScopesOneMatches(@TempDir Path tempDir) throws IOExcept
284286
assertThat(scopeInfo.getName()).isEqualTo("io.opentelemetry.hibernate-6.0");
285287
assertThat(scopeInfo.getSchemaUrl()).isEqualTo("https://opentelemetry.io/schemas/1.21.0");
286288
}
289+
290+
@Test
291+
void testGetScopeWithStringAttributes(@TempDir Path tempDir) throws IOException {
292+
Path instrumentationDir = tempDir.resolve("test-instrumentation");
293+
Path telemetryDir = instrumentationDir.resolve(".telemetry");
294+
Files.createDirectories(telemetryDir);
295+
296+
String scopeContent =
297+
"""
298+
scopes:
299+
- name: io.opentelemetry.jdbc
300+
version: 2.14.0
301+
schemaUrl: null
302+
attributes:
303+
test.key: test-value
304+
another.key: another-value
305+
""";
306+
307+
Files.writeString(telemetryDir.resolve("scope-with-attrs.yaml"), scopeContent);
308+
309+
FileManager fileManager = new FileManager(tempDir + "/");
310+
InstrumentationModule module =
311+
new InstrumentationModule.Builder()
312+
.srcPath("test-instrumentation")
313+
.instrumentationName("jdbc")
314+
.namespace("jdbc")
315+
.group("jdbc")
316+
.build();
317+
318+
InstrumentationScopeInfo scopeInfo = EmittedScopeParser.getScope(fileManager, module);
319+
320+
assertThat(scopeInfo).isNotNull();
321+
assertThat(scopeInfo.getName()).isEqualTo("io.opentelemetry.jdbc");
322+
assertThat(scopeInfo.getAttributes()).isNotNull();
323+
assertThat(scopeInfo.getAttributes().get(stringKey("test.key"))).isEqualTo("test-value");
324+
assertThat(scopeInfo.getAttributes().get(stringKey("another.key"))).isEqualTo("another-value");
325+
}
326+
327+
@Test
328+
void testGetScopeWithMixedTypeAttributes(@TempDir Path tempDir) throws IOException {
329+
Path instrumentationDir = tempDir.resolve("test-instrumentation");
330+
Path telemetryDir = instrumentationDir.resolve(".telemetry");
331+
Files.createDirectories(telemetryDir);
332+
333+
String scopeContent =
334+
"""
335+
scopes:
336+
- name: io.opentelemetry.test-lib
337+
version: 1.0.0
338+
schemaUrl: null
339+
attributes:
340+
string.key: string-value
341+
int.key: 123
342+
long.key: 9876543210
343+
double.key: 3.14
344+
bool.key: true
345+
""";
346+
347+
Files.writeString(telemetryDir.resolve("scope-mixed-attrs.yaml"), scopeContent);
348+
349+
FileManager fileManager = new FileManager(tempDir + "/");
350+
InstrumentationModule module =
351+
new InstrumentationModule.Builder()
352+
.srcPath("test-instrumentation")
353+
.instrumentationName("test-lib")
354+
.namespace("test-lib")
355+
.group("test-lib")
356+
.build();
357+
358+
InstrumentationScopeInfo scopeInfo = EmittedScopeParser.getScope(fileManager, module);
359+
360+
assertThat(scopeInfo).isNotNull();
361+
assertThat(scopeInfo.getAttributes()).isNotNull();
362+
assertThat(scopeInfo.getAttributes().get(stringKey("string.key"))).isEqualTo("string-value");
363+
assertThat(scopeInfo.getAttributes().get(AttributeKey.longKey("int.key"))).isEqualTo(123L);
364+
assertThat(scopeInfo.getAttributes().get(AttributeKey.longKey("long.key")))
365+
.isEqualTo(9876543210L);
366+
assertThat(scopeInfo.getAttributes().get(AttributeKey.doubleKey("double.key"))).isEqualTo(3.14);
367+
assertThat(scopeInfo.getAttributes().get(AttributeKey.booleanKey("bool.key"))).isTrue();
368+
}
369+
370+
@Test
371+
void testScopeEqualityWithAttributes(@TempDir Path tempDir) throws IOException {
372+
Path instrumentationDir = tempDir.resolve("test-instrumentation");
373+
Path telemetryDir = instrumentationDir.resolve(".telemetry");
374+
Files.createDirectories(telemetryDir);
375+
376+
String scopeContent1 =
377+
"""
378+
scopes:
379+
- name: io.opentelemetry.test
380+
version: 1.0.0
381+
schemaUrl: null
382+
attributes:
383+
key1: value1
384+
""";
385+
386+
String scopeContent2 =
387+
"""
388+
scopes:
389+
- name: io.opentelemetry.test
390+
version: 1.0.0
391+
schemaUrl: null
392+
attributes:
393+
key1: value1
394+
""";
395+
396+
Files.writeString(telemetryDir.resolve("scope-1.yaml"), scopeContent1);
397+
Files.writeString(telemetryDir.resolve("scope-2.yaml"), scopeContent2);
398+
399+
Set<EmittedScope.Scope> scopes =
400+
EmittedScopeParser.getScopesFromFiles(tempDir.toString(), "test-instrumentation");
401+
402+
assertThat(scopes).hasSize(1);
403+
}
404+
405+
@Test
406+
void testScopeInequalityWithDifferentAttributes(@TempDir Path tempDir) throws IOException {
407+
Path instrumentationDir = tempDir.resolve("test-instrumentation");
408+
Path telemetryDir = instrumentationDir.resolve(".telemetry");
409+
Files.createDirectories(telemetryDir);
410+
411+
String scopeContent1 =
412+
"""
413+
scopes:
414+
- name: io.opentelemetry.test
415+
version: 1.0.0
416+
schemaUrl: null
417+
attributes:
418+
key1: value1
419+
""";
420+
421+
String scopeContent2 =
422+
"""
423+
scopes:
424+
- name: io.opentelemetry.test
425+
version: 1.0.0
426+
schemaUrl: null
427+
attributes:
428+
key1: value2
429+
""";
430+
431+
Files.writeString(telemetryDir.resolve("scope-1.yaml"), scopeContent1);
432+
Files.writeString(telemetryDir.resolve("scope-2.yaml"), scopeContent2);
433+
434+
Set<EmittedScope.Scope> scopes =
435+
EmittedScopeParser.getScopesFromFiles(tempDir.toString(), "test-instrumentation");
436+
437+
assertThat(scopes).hasSize(2);
438+
}
287439
}

instrumentation-docs/src/test/java/io/opentelemetry/instrumentation/docs/utils/YamlHelperTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import static org.assertj.core.api.Assertions.assertThat;
1212

1313
import com.fasterxml.jackson.core.JsonProcessingException;
14+
import io.opentelemetry.api.common.Attributes;
1415
import io.opentelemetry.instrumentation.docs.internal.ConfigurationOption;
1516
import io.opentelemetry.instrumentation.docs.internal.ConfigurationType;
1617
import io.opentelemetry.instrumentation.docs.internal.EmittedMetrics;
@@ -59,6 +60,11 @@ void testPrintInstrumentationList() throws Exception {
5960
InstrumentationScopeInfo.builder("io.opentelemetry.spring-web-6.0")
6061
.setVersion("2.14.0")
6162
.setSchemaUrl("http:://www.schema.org")
63+
.setAttributes(
64+
Attributes.builder()
65+
.put("instrumentation.type", "library")
66+
.put("version.major", 6L)
67+
.build())
6268
.build())
6369
.namespace("spring")
6470
.group("spring")
@@ -103,6 +109,9 @@ void testPrintInstrumentationList() throws Exception {
103109
scope:
104110
name: io.opentelemetry.spring-web-6.0
105111
schema_url: http:://www.schema.org
112+
attributes:
113+
instrumentation.type: library
114+
version.major: 6
106115
target_versions:
107116
javaagent:
108117
- org.springframework:spring-web:[6.0.0,)

0 commit comments

Comments
 (0)