Skip to content

Commit 2a7a553

Browse files
jack-berglaurit
andauthored
Add declarative config support for resource providers (#12144)
Co-authored-by: Lauri Tulmin <[email protected]>
1 parent eb6624b commit 2a7a553

13 files changed

+453
-158
lines changed

instrumentation/resources/library/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Provider: `io.opentelemetry.instrumentation.resources.ContainerResource`
1111

1212
Specification: <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/container.md>
1313

14+
Included in [declarative config].
15+
1416
Implemented attributes:
1517

1618
- `container.id`
@@ -21,6 +23,8 @@ Provider: `io.opentelemetry.instrumentation.resources.HostResource`
2123

2224
Specification: <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/host.md>
2325

26+
Included in [declarative config].
27+
2428
Implemented attributes:
2529

2630
- `host.name`
@@ -30,6 +34,8 @@ Provider: `io.opentelemetry.instrumentation.resources.HostIdResourceProvider`
3034

3135
Specification: <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/host.md>
3236

37+
Included in [declarative config].
38+
3339
Implemented attributes:
3440

3541
- `host.id`
@@ -40,6 +46,8 @@ Provider: `io.opentelemetry.instrumentation.resources.OsResource`
4046

4147
Specification: <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/os.md>
4248

49+
Included in [declarative config].
50+
4351
Implemented attributes:
4452

4553
- `os.type`
@@ -51,6 +59,8 @@ Implementation: `io.opentelemetry.instrumentation.resources.ProcessResource`
5159

5260
Specification: <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/process.md#process>
5361

62+
Included in [declarative config].
63+
5464
Implemented attributes:
5565

5666
- `process.pid`
@@ -63,6 +73,8 @@ Implementation: `io.opentelemetry.instrumentation.resources.ProcessRuntimeResour
6373

6474
Specification: <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/process.md#process-runtimes>
6575

76+
Included in [declarative config].
77+
6678
Implemented attributes:
6779

6880
- `process.runtime.name`
@@ -73,3 +85,5 @@ Implemented attributes:
7385

7486
This package currently does not run on Android. It has been verified on OpenJDK and should work on
7587
other server JVM distributions but if you find any issues please let us know.
88+
89+
[declarative config]: https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/configuration#declarative-configuration

instrumentation/resources/library/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dependencies {
1212
annotationProcessor("com.google.auto.service:auto-service")
1313
compileOnly("com.google.auto.service:auto-service-annotations")
1414
testCompileOnly("com.google.auto.service:auto-service-annotations")
15+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator")
1516

1617
testImplementation("org.junit.jupiter:junit-jupiter-api")
1718
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.resources;
7+
8+
import static java.util.logging.Level.FINE;
9+
10+
import io.opentelemetry.api.common.AttributeKey;
11+
import io.opentelemetry.api.common.Attributes;
12+
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
13+
import io.opentelemetry.sdk.resources.Resource;
14+
import java.io.BufferedReader;
15+
import java.io.IOException;
16+
import java.io.InputStreamReader;
17+
import java.nio.charset.StandardCharsets;
18+
import java.nio.file.FileSystems;
19+
import java.nio.file.Files;
20+
import java.nio.file.Path;
21+
import java.util.ArrayList;
22+
import java.util.Collections;
23+
import java.util.List;
24+
import java.util.Locale;
25+
import java.util.function.Function;
26+
import java.util.function.Supplier;
27+
import java.util.logging.Logger;
28+
29+
/**
30+
* {@link ResourceProvider} for automatically configuring <code>host.id</code> according to <a
31+
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/host.md#non-privileged-machine-id-lookup">the
32+
* semantic conventions</a>
33+
*/
34+
public final class HostIdResource {
35+
36+
private static final Logger logger = Logger.getLogger(HostIdResource.class.getName());
37+
38+
// copied from HostIncubatingAttributes
39+
static final AttributeKey<String> HOST_ID = AttributeKey.stringKey("host.id");
40+
41+
public static final String REGISTRY_QUERY =
42+
"reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography /v MachineGuid";
43+
44+
private static final HostIdResource INSTANCE =
45+
new HostIdResource(
46+
HostIdResource::getOsTypeSystemProperty,
47+
HostIdResource::readMachineIdFile,
48+
HostIdResource::queryWindowsRegistry);
49+
50+
private final Supplier<String> getOsType;
51+
private final Function<Path, List<String>> machineIdReader;
52+
private final Supplier<List<String>> queryWindowsRegistry;
53+
54+
// Visible for testing
55+
HostIdResource(
56+
Supplier<String> getOsType,
57+
Function<Path, List<String>> machineIdReader,
58+
Supplier<List<String>> queryWindowsRegistry) {
59+
this.getOsType = getOsType;
60+
this.machineIdReader = machineIdReader;
61+
this.queryWindowsRegistry = queryWindowsRegistry;
62+
}
63+
64+
/** Returns a {@link Resource} containing the {@code host.id} resource attribute. */
65+
public static Resource get() {
66+
return INSTANCE.createResource();
67+
}
68+
69+
/** Returns a {@link Resource} containing the {@code host.id} resource attribute. */
70+
Resource createResource() {
71+
if (runningWindows()) {
72+
return readWindowsGuid();
73+
}
74+
if (runningLinux()) {
75+
return readLinuxMachineId();
76+
}
77+
logger.log(FINE, "Unsupported OS type: {0}", getOsType.get());
78+
return Resource.empty();
79+
}
80+
81+
private boolean runningLinux() {
82+
return getOsType.get().toLowerCase(Locale.ROOT).equals("linux");
83+
}
84+
85+
private boolean runningWindows() {
86+
return getOsType.get().startsWith("Windows");
87+
}
88+
89+
// see
90+
// https://github.com/apache/commons-lang/blob/master/src/main/java/org/apache/commons/lang3/SystemUtils.java
91+
// for values
92+
private static String getOsTypeSystemProperty() {
93+
return System.getProperty("os.name", "");
94+
}
95+
96+
private Resource readLinuxMachineId() {
97+
Path path = FileSystems.getDefault().getPath("/etc/machine-id");
98+
List<String> lines = machineIdReader.apply(path);
99+
if (lines.isEmpty()) {
100+
return Resource.empty();
101+
}
102+
return Resource.create(Attributes.of(HOST_ID, lines.get(0)));
103+
}
104+
105+
private static List<String> readMachineIdFile(Path path) {
106+
try {
107+
List<String> lines = Files.readAllLines(path);
108+
if (lines.isEmpty()) {
109+
logger.fine("Failed to read /etc/machine-id: empty file");
110+
}
111+
return lines;
112+
} catch (IOException e) {
113+
logger.log(FINE, "Failed to read /etc/machine-id", e);
114+
return Collections.emptyList();
115+
}
116+
}
117+
118+
private Resource readWindowsGuid() {
119+
List<String> lines = queryWindowsRegistry.get();
120+
121+
for (String line : lines) {
122+
if (line.contains("MachineGuid")) {
123+
String[] parts = line.trim().split("\\s+");
124+
if (parts.length == 3) {
125+
return Resource.create(Attributes.of(HOST_ID, parts[2]));
126+
}
127+
}
128+
}
129+
logger.fine("Failed to read Windows registry: No MachineGuid found in output: " + lines);
130+
return Resource.empty();
131+
}
132+
133+
private static List<String> queryWindowsRegistry() {
134+
try {
135+
ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/c", REGISTRY_QUERY);
136+
processBuilder.redirectErrorStream(true);
137+
Process process = processBuilder.start();
138+
139+
List<String> output = getProcessOutput(process);
140+
int exitedValue = process.waitFor();
141+
if (exitedValue != 0) {
142+
logger.fine(
143+
"Failed to read Windows registry. Exit code: "
144+
+ exitedValue
145+
+ " Output: "
146+
+ String.join("\n", output));
147+
148+
return Collections.emptyList();
149+
}
150+
151+
return output;
152+
} catch (IOException | InterruptedException e) {
153+
logger.log(FINE, "Failed to read Windows registry", e);
154+
return Collections.emptyList();
155+
}
156+
}
157+
158+
private static List<String> getProcessOutput(Process process) throws IOException {
159+
List<String> result = new ArrayList<>();
160+
161+
try (BufferedReader processOutputReader =
162+
new BufferedReader(
163+
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
164+
String readLine;
165+
166+
while ((readLine = processOutputReader.readLine()) != null) {
167+
result.add(readLine);
168+
}
169+
}
170+
return result;
171+
}
172+
}

0 commit comments

Comments
 (0)