Skip to content

Commit 7ee399e

Browse files
[#175]: implemented the opentelemetry metrics export using the function in the common crate
1 parent 149abf6 commit 7ee399e

3 files changed

Lines changed: 104 additions & 53 deletions

File tree

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
11
use anyhow::anyhow;
22
use aya::util::online_cpus;
33
use cortexbrain_common::map_handlers::map_manager;
4-
use cortexbrain_common::{
5-
buffer_type::{BufferSize, BufferType, read_perf_buffer},
6-
map_handlers::BpfMapsData,
7-
};
4+
use cortexbrain_common::{buffer_type::BufferSize, map_handlers::BpfMapsData};
5+
use opentelemetry::metrics::Meter;
6+
use std::sync::Arc;
87
use tokio::signal;
98
use tracing::{error, info};
109

11-
pub async fn event_listener(bpf_maps: BpfMapsData) -> Result<(), anyhow::Error> {
10+
use cortexbrain_common::buffer_type::{BufferType, read_perf_buffer};
11+
use cortexbrain_common::otel_metrics::Metrics;
12+
13+
/// Listen for eBPF perf-buffer events and record OpenTelemetry metrics.
14+
///
15+
/// This function bridges the eBPF perf-buffer layer with the OpenTelemetry
16+
/// metrics pipeline. It opens per-CPU buffers for the two maps of interest
17+
/// (`net_metrics` and `time_stamp_events`), spawns asynchronous consumers,
18+
/// and parks until a `Ctrl-C` signal is received or one of the consumers
19+
/// terminates.
20+
///
21+
/// # Arguments
22+
///
23+
/// -`bpf_maps` – handles for the pinned BPF maps produced by
24+
/// [`cortexbrain_common::map_handlers::map_pinner`].
25+
/// - `meter` – an initialised OpenTelemetry [`Meter`].
26+
///
27+
/// # Errors
28+
///
29+
/// Returns `Err` if the map manager or CPU enumeration fails.
30+
///
31+
pub async fn event_listener(bpf_maps: BpfMapsData, meter: Meter) -> Result<(), anyhow::Error> {
1232
info!("Getting CPU count...");
1333

1434
let mut maps = map_manager(bpf_maps)?;
@@ -35,48 +55,63 @@ pub async fn event_listener(bpf_maps: BpfMapsData) -> Result<(), anyhow::Error>
3555

3656
info!("Perf buffers created successfully");
3757

38-
let (time_stamp_events_array, time_stamp_events_perf_buffer) = maps
58+
let (_time_stamp_events_array, time_stamp_events_perf_buffer) = maps
3959
.remove("time_stamp_events")
4060
.expect("Cannot create time_stamp_events_buffer");
41-
let (net_perf_array, net_perf_buffer) = maps
61+
let (_net_perf_array, net_perf_buffer) = maps
4262
.remove("net_metrics")
4363
.expect("Cannot create net_perf_buffer");
4464

45-
// Create proper sized buffers
65+
// Allocate byte-buffers sized for each structure type
4666
let net_metrics_buffers = BufferSize::NetworkMetricsEvents.set_buffer();
4767
let time_stamp_events_buffers = BufferSize::TimeMetricsEvents.set_buffer();
4868

69+
let metrics = Arc::new(Metrics::new(&meter));
70+
4971
info!("Starting event listener tasks...");
50-
let metrics_map_displayer = tokio::spawn(async move {
51-
read_perf_buffer(
52-
net_perf_buffer,
53-
net_metrics_buffers,
54-
BufferType::NetworkMetrics,
55-
)
56-
.await;
57-
});
58-
59-
let time_stamp_events_displayer = tokio::spawn(async move {
60-
read_perf_buffer(
61-
time_stamp_events_perf_buffer,
62-
time_stamp_events_buffers,
63-
BufferType::TimeStampMetrics,
64-
)
65-
.await;
66-
});
72+
73+
let net_metrics_handle = {
74+
let metrics = Arc::clone(&metrics);
75+
let mut array_buffers = net_perf_buffer;
76+
let mut buffers = net_metrics_buffers;
77+
tokio::spawn(async move {
78+
read_perf_buffer(
79+
array_buffers,
80+
buffers,
81+
BufferType::NetworkMetrics,
82+
Some(metrics),
83+
)
84+
.await;
85+
})
86+
};
87+
88+
let time_stamp_handle = {
89+
let metrics = Arc::clone(&metrics);
90+
let mut array_buffers = time_stamp_events_perf_buffer;
91+
let mut buffers = time_stamp_events_buffers;
92+
tokio::spawn(async move {
93+
read_perf_buffer(
94+
array_buffers,
95+
buffers,
96+
BufferType::TimeStampMetrics,
97+
Some(metrics),
98+
)
99+
.await;
100+
})
101+
};
67102

68103
info!("Event listeners started, entering main loop...");
69104

70105
tokio::select! {
71-
result = metrics_map_displayer => {
106+
result = net_metrics_handle => {
72107
if let Err(e) = result {
73-
error!("Metrics map displayer task failed: {:?}", e);
108+
error!("Network metrics task failed: {:?}", e);
74109
}
75110
}
76111

77-
result = time_stamp_events_displayer => {
112+
result = time_stamp_handle => {
78113
if let Err(e) = result {
79-
error!("Time stamp events displayer task failed: {:?}", e);
114+
error!("Timestamp events task failed: {:?}", e);
80115
}
81116
}
82117

@@ -85,6 +120,5 @@ pub async fn event_listener(bpf_maps: BpfMapsData) -> Result<(), anyhow::Error>
85120
}
86121
}
87122

88-
// return success
89123
Ok(())
90124
}
Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1-
use anyhow::{Context, Ok};
1+
//! CortexBrain metrics service – eBPF-based telemetry with OpenTelemetry export.
2+
//!
3+
//! This binary is the node-level metrics agent for CortexBrain. It:
4+
//!
5+
//! 1. Initialises an OpenTelemetry metrics pipeline (OTLP / gRPC).
6+
//! 2. Loads a compiled eBPF object and pins its maps to the BPF filesystem.
7+
//! 3. Attaches a set of kernel kprobe programs.
8+
//! 4. Starts asynchronous consumers that read per-CPU perf buffers and
9+
//! emit OpenTelemetry instruments for every event.
10+
//! 5. Blocks until `Ctrl-C` is received, then shuts down cleanly.
11+
12+
use anyhow::Context;
213
use aya::Ebpf;
314
use std::{
415
env, fs,
516
path::Path,
617
sync::{Arc, Mutex},
718
};
819
use tracing::{error, info};
9-
1020
mod helpers;
21+
mod otel_init;
1122
use crate::helpers::event_listener;
23+
use crate::otel_init::{init_opentelemetry, shutdown_opentelemetry};
1224

1325
use cortexbrain_common::{
1426
constants,
@@ -19,12 +31,14 @@ use cortexbrain_common::{
1931

2032
#[tokio::main]
2133
async fn main() -> Result<(), anyhow::Error> {
22-
//init tracing subscriber
23-
let otlp_provider = otlp_logger_init("metrics-service".to_string());
34+
let _otlp_log_provider = otlp_logger_init("metrics-service".to_string());
2435

2536
info!("Starting metrics service...");
2637
info!("fetching data");
2738

39+
let meter =
40+
init_opentelemetry().context("Failed to initialise OpenTelemetry metrics pipeline")?;
41+
2842
let bpf_path =
2943
env::var(constants::BPF_PATH).context("BPF_PATH environment variable required")?;
3044
let data = fs::read(Path::new(&bpf_path)).context("Failed to load file from path")?;
@@ -35,54 +49,58 @@ async fn main() -> Result<(), anyhow::Error> {
3549

3650
info!("Running Ebpf logger");
3751
info!("loading programs");
38-
let bpf_map_save_path = std::env::var(constants::PIN_MAP_PATH)
39-
.context("PIN_MAP_PATH environment variable required")?;
52+
53+
let bpf_map_save_path =
54+
env::var(constants::PIN_MAP_PATH).context("PIN_MAP_PATH environment variable required")?;
4055

4156
let map_data = vec!["time_stamp_events".to_string(), "net_metrics".to_string()];
4257

4358
match init_bpf_maps(bpf.clone(), map_data) {
44-
std::result::Result::Ok(bpf_maps) => {
59+
Ok(bpf_maps) => {
4560
info!("BPF maps loaded successfully");
4661
let pin_path = std::path::PathBuf::from(&bpf_map_save_path);
4762
info!("About to call map_pinner with path: {:?}", pin_path);
63+
4864
match map_pinner(bpf_maps, &pin_path) {
49-
std::result::Result::Ok(maps) => {
65+
Ok(maps) => {
5066
info!("BPF maps pinned successfully to {}", bpf_map_save_path);
5167

5268
{
5369
load_program(bpf.clone(), "metrics_tracer", "tcp_identify_packet_loss")
5470
.context(
55-
"An error occured during the execution of load_program function",
71+
"An error occurred during the execution of load_program function",
5672
)?;
5773

58-
load_program(tcp_bpf,"tcp_v4_connect","tcp_v4_connect")
59-
.context("An error occured during the execution of load_and_attach_tcp_programs function")?;
60-
load_program(tcp_v6_bpf,"tcp_v6_connect","tcp_v6_connect")
61-
.context("An error occured during the execution of load_and_attach_tcp_programs function")?;
74+
load_program(tcp_bpf, "tcp_v4_connect", "tcp_v4_connect")
75+
.context("An error occurred during the execution of load_and_attach_tcp_programs function")?;
76+
77+
load_program(tcp_v6_bpf, "tcp_v6_connect", "tcp_v6_connect")
78+
.context("An error occurred during the execution of load_and_attach_tcp_programs function")?;
6279

6380
load_program(
6481
tcp_rev_bpf,
6582
"tcp_rcv_state_process",
6683
"tcp_rcv_state_process",
6784
)
6885
.context(
69-
"An error occured during the execution of load_program function",
86+
"An error occurred during the execution of load_program function",
7087
)?;
7188
}
72-
event_listener(maps).await?;
89+
90+
// Hand off to the async event consumer
91+
event_listener(maps, meter).await
7392
}
7493
Err(e) => {
7594
error!("Error pinning BPF maps: {:?}", e);
76-
return Err(e);
95+
shutdown_opentelemetry();
96+
Err(e)
7797
}
7898
}
7999
}
80100
Err(e) => {
81101
error!("Error initializing BPF maps: {:?}", e);
82-
let _ = otlp_provider.shutdown();
83-
return Err(e);
102+
shutdown_opentelemetry();
103+
Err(e)
84104
}
85105
}
86-
87-
Ok(())
88106
}
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
mod structs;
2-
mod enums;
3-
mod helpers;
1+
mod helpers;
2+
mod otel_init;

0 commit comments

Comments
 (0)