From 9fb1d10e84f7ffa28006dc9787c16156bd4db2ee Mon Sep 17 00:00:00 2001 From: LorenzoTettamanti Date: Mon, 24 Aug 2026 16:35:27 +0200 Subject: [PATCH 1/9] (fix): fix dockerfile for metrics build after the latest bpf-linker update --- core/src/components/metrics/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/components/metrics/Dockerfile b/core/src/components/metrics/Dockerfile index 09b4e6a1..111590e2 100644 --- a/core/src/components/metrics/Dockerfile +++ b/core/src/components/metrics/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y \ && rm -rf /var/lib/apt/lists/* RUN cargo install --locked bindgen-cli -RUN cargo install --locked bpf-linker +RUN cargo install --locked bpf-linker@0.10.4 RUN rustup toolchain install nightly --component rust-src WORKDIR /usr/src/app From e2d9124146377b7ccda29746e7b5112850751b76 Mon Sep 17 00:00:00 2001 From: LorenzoTettamanti Date: Mon, 24 Aug 2026 16:37:00 +0200 Subject: [PATCH 2/9] (fix): fixed "null" in container.name when using Docker. --- core/Cargo.lock | 2 +- core/common/src/metadata.rs | 174 +++++++++++++++++++++++-- core/common/src/otel_metrics.rs | 14 +- core/src/components/metrics/Cargo.toml | 2 +- core/src/testing/metrics.yaml | 2 +- 5 files changed, 173 insertions(+), 21 deletions(-) diff --git a/core/Cargo.lock b/core/Cargo.lock index b5bb8f71..4a48b5b1 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -458,7 +458,7 @@ dependencies = [ "aya-log", "bytemuck", "bytes", - "cortexbrain-common 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cortexbrain-common 0.1.2", "libc", "nix", "opentelemetry", diff --git a/core/common/src/metadata.rs b/core/common/src/metadata.rs index 9c97bbb1..2072dd66 100644 --- a/core/common/src/metadata.rs +++ b/core/common/src/metadata.rs @@ -1,4 +1,11 @@ +use std::collections::HashMap; use std::fs; +use anyhow::Error; +use k8s_openapi::api::core::v1::Pod; +use kube::api::ObjectList; +use kube::{Api, Client}; +use tracing::debug; + /// Detected container runtime. #[derive(Debug, Clone, PartialEq)] @@ -47,11 +54,11 @@ impl Metadata { /// 4. If Docker is not found, attempts K8s lookup. pub fn enrich(&mut self) { self.try_resolve_docker(); - // K8s lookup will be enabled later with an LRU cache. + self.try_resolve_k8s(); } /// Docker resolution via local filesystem. - /// + /// This part is triggered when the container is already detected // TODO: this is working for Linux, can anyone check if this works on macOs systems ? fn try_resolve_docker(&mut self) { let Some(tgid) = self.tgid else { return }; @@ -84,17 +91,62 @@ impl Metadata { // Step 3: resolve container name from Docker metadata JSON match resolve_docker_name(&id) { Some(name) => self.container_name = Some(name), - None => self.container_name = Some("null".to_string()), + None => { + self.container_name = + Some(self.container_id.clone()).expect("Cannot resolve container name") + } // fallback to the container_id if the system cannot resolve the name after the 2 steps } } } - /// Manual enrichment from Kubernetes (for external use, e.g. identity service). - pub fn enrich_from_k8s(&mut self, pod_name: impl Into, namespace: impl Into) { - self.runtime = ContainerRuntime::Kubernetes; - self.pod_name = Some(pod_name.into()); - self.namespace = Some(namespace.into()); + fn try_resolve_k8s(&mut self){ + let Some(tgid) = self.tgid else { return }; + + // Step 1: read the cgroup path from procfs + let cgroup_info = match fs::read_to_string(format!("/proc/{}/cgroup", tgid)) { + Ok(s) => s, + Err(e) => { + tracing::debug!("Cannot read /proc/{}/cgroup: {}", tgid, e); + return; + } + }; + + // Extract the actual path from the cgroup file (format: hierarchy:id:path) + let cgroup_path = cgroup_info + .lines() + .filter_map(|line| line.split(':').nth(2)) + .next() + .unwrap_or(""); + + if cgroup_path.is_empty() { + return; + } + + // Step 2: extract container ID from the path + if let Some(id) = extract_container_id_from_path(cgroup_path) { + self.container_id = Some(id.clone()); + self.runtime = ContainerRuntime::Kubernetes; + + // Step 3: resolve container name from Docker metadata JSON + match resolve_k8s_name(&id) { + Some(name) => self.container_name = Some(name), + None => { + self.container_name = + Some(self.container_id.clone()).expect("Cannot resolve container name from k8s api ") + } // fallback to the container_id if the system cannot resolve the name after the 2 steps + } + } + + //Step 3: call the k8s API to solve the container nam e } + + // TODO: dead code + // Enrichment from Kubernetes (for external use, e.g. identity service). + //pub fn enrich_from_k8s(&mut self, pod_name: impl Into, namespace: impl Into) { + // self.runtime = ContainerRuntime::Kubernetes; + // self.pod_name = Some(pod_name.into()); + // self.namespace = Some(namespace.into()); + //} } /// Extract the container ID from a cgroup path, supporting multiple prefixes. @@ -134,14 +186,116 @@ fn resolve_docker_name(container_id: &str) -> Option { let path = format!("/var/lib/docker/containers/{}/config.v2.json", container_id); let json_str = fs::read_to_string(&path).ok()?; let parsed: serde_json::Value = serde_json::from_str(&json_str).ok()?; - let image_name = parsed + let mut image_name = parsed .get("Config")? .get("Image")? .as_str()? .trim_start_matches('/'); + if image_name.is_empty() { + image_name = parsed + .get("Config")? + .get("WorkingDir")? + .as_str()? + .trim_start_matches('/'); // fallback if the image_name is empty + } + Some(image_name.to_string()) } + +fn resolve_k8s_name(container_id: &str) -> Option { + // pass a container_id and returns the object meta infos: + /* pub struct ObjectMeta { + + pub annotations: Option>, + pub creation_timestamp: Option