Skip to content

Commit a96fe8b

Browse files
authored
Add container.id to resource attributes (#129)
* Add container.id to resource attributes Signed-off-by: Pavol Loffay <[email protected]> * Add comments Signed-off-by: Pavol Loffay <[email protected]> * Adjust message Signed-off-by: Pavol Loffay <[email protected]> * fix Signed-off-by: Pavol Loffay <[email protected]>
1 parent 36f0f6a commit a96fe8b

File tree

9 files changed

+172
-0
lines changed

9 files changed

+172
-0
lines changed

instrumentation/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies{
3434
implementation(project(":instrumentation:spark-web-framework-2.3"))
3535
implementation(project(":instrumentation:grpc-1.5"))
3636
implementation(project(":instrumentation:okhttp:okhttp-3.0"))
37+
implementation(project(":otel-extensions"))
3738
}
3839

3940
tasks {

javaagent-core/src/main/resources/META-INF/services/io.opentelemetry.sdk.resources.ResourceProvider

Whitespace-only changes.

otel-extensions/build.gradle.kts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
plugins {
2+
`java-library`
3+
}
4+
5+
dependencies {
6+
implementation("org.slf4j:slf4j-api:1.7.30")
7+
compileOnly("io.opentelemetry:opentelemetry-sdk:0.10.0")
8+
implementation("com.google.auto.service:auto-service:1.0-rc7")
9+
annotationProcessor("com.google.auto.service:auto-service:1.0-rc7")
10+
11+
testImplementation("io.opentelemetry:opentelemetry-sdk:0.10.0")
12+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright The Hypertrace Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.hypertrace.agent.otel.extensions;
18+
19+
import java.io.BufferedReader;
20+
import java.io.FileNotFoundException;
21+
import java.io.FileReader;
22+
import java.io.IOException;
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
public class CgroupsReader {
27+
28+
private static final Logger log =
29+
LoggerFactory.getLogger(HypertraceResourceProvider.class.getName());
30+
31+
private static final String DEFAULT_CGROUPS_PATH = "/proc/self/cgroup";
32+
private static final int CONTAINER_ID_LENGTH = 64;
33+
34+
private final String cgroupsPath;
35+
36+
CgroupsReader() {
37+
this.cgroupsPath = DEFAULT_CGROUPS_PATH;
38+
}
39+
40+
CgroupsReader(String cgroupsPath) {
41+
this.cgroupsPath = cgroupsPath;
42+
}
43+
44+
/**
45+
* Read container ID from cgroups file.
46+
*
47+
* @return docker container ID or empty string if not defined.
48+
*/
49+
@SuppressWarnings("DefaultCharset")
50+
public String readContainerId() {
51+
try (BufferedReader br = new BufferedReader(new FileReader(cgroupsPath))) {
52+
String line;
53+
while ((line = br.readLine()) != null) {
54+
if (line.length() > CONTAINER_ID_LENGTH) {
55+
String id = line.substring(line.length() - CONTAINER_ID_LENGTH);
56+
if (!id.contains("/")) {
57+
return id;
58+
}
59+
}
60+
}
61+
} catch (FileNotFoundException ex) {
62+
// do not pass exception to logger because it prints stacktrace, we don't want that in non
63+
// container environments
64+
log.warn("Failed to read container id, cgroups file does not exist: {}", ex.getMessage());
65+
} catch (IOException ex) {
66+
log.warn("Unable to read container id", ex);
67+
}
68+
return "";
69+
}
70+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright The Hypertrace Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.hypertrace.agent.otel.extensions;
18+
19+
import com.google.auto.service.AutoService;
20+
import io.opentelemetry.api.common.Attributes;
21+
import io.opentelemetry.api.common.Attributes.Builder;
22+
import io.opentelemetry.sdk.resources.ResourceAttributes;
23+
import io.opentelemetry.sdk.resources.ResourceProvider;
24+
25+
@AutoService(ResourceProvider.class)
26+
public class HypertraceResourceProvider extends ResourceProvider {
27+
28+
private final CgroupsReader cgroupsReader = new CgroupsReader();
29+
30+
@Override
31+
protected Attributes getAttributes() {
32+
Builder builder = Attributes.builder();
33+
String containerId = this.cgroupsReader.readContainerId();
34+
if (containerId != null && !containerId.isEmpty()) {
35+
builder.put(ResourceAttributes.CONTAINER_ID.getKey(), containerId);
36+
}
37+
return builder.build();
38+
}
39+
}

otel-extensions/src/main/resources/io.opentelemetry.sdk.resources.ResourceProvider

Whitespace-only changes.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright The Hypertrace Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.hypertrace.agent.otel.extensions;
18+
19+
import com.google.common.base.Charsets;
20+
import com.google.common.io.Files;
21+
import java.io.File;
22+
import java.io.IOException;
23+
import org.junit.jupiter.api.Assertions;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.io.TempDir;
26+
27+
public class DockerCgroupsReaderTest {
28+
29+
@Test
30+
void testCgroupFileMissing() {
31+
CgroupsReader cgroups = new CgroupsReader("doesnotexists");
32+
Assertions.assertEquals("", cgroups.readContainerId());
33+
}
34+
35+
@Test
36+
void readContainerId(@TempDir File tempFolder) throws IOException {
37+
File file = new File(tempFolder, "cgroup");
38+
String expected = "987a1920640799b5bf5a39bd94e489e5159a88677d96ca822ce7c433ff350163";
39+
String content = "dummy\n11:devices:/ecs/bbc36dd0-5ee0-4007-ba96-c590e0b278d2/" + expected;
40+
Files.write(content.getBytes(Charsets.UTF_8), file);
41+
42+
CgroupsReader cgroupsReader = new CgroupsReader(file.getPath());
43+
Assertions.assertEquals(expected, cgroupsReader.readContainerId());
44+
}
45+
}

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ findProject(":instrumentation:grpc-1.5")?.name = "grpc-1.5"
3535
include("instrumentation:okhttp:okhttp-3.0")
3636
findProject(":instrumentation:okhttp:okhttp-3.0")?.name = "okhttp-3.0"
3737
include("filter-custom-opa")
38+
include("otel-extensions")

smoke-tests/src/test/java/org/hypertrace/agent/smoketest/SpringBootSmokeTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ public void get() throws IOException {
113113
.map(attribute -> attribute.getValue().getStringValue())
114114
.count()
115115
> 0);
116+
// TODO test the container ID once we switch from Zipkin exporter
117+
// Zipkin exporter does not add resource attributes to span
118+
// https://github.com/open-telemetry/opentelemetry-java/issues/1970
119+
116120
// OTEL BS smoke test app does not have an endpoint that uses content type what we capture
117121
// enable once we add smoke tests apps to our build.
118122
// List<String> responseBodyAttributes =

0 commit comments

Comments
 (0)