diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index e24acfb4..3dd5b171 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -60,10 +60,12 @@ use std::{ const MAP_NAME: &str = "AYA_LOGS"; use aya::{ + loaded_programs, maps::{ perf::{AsyncPerfEventArray, Events, PerfBufferError}, - MapError, + Map, MapData, MapError, MapInfo, }, + programs::ProgramError, util::online_cpus, Ebpf, Pod, }; @@ -112,12 +114,54 @@ impl EbpfLogger { bpf: &mut Ebpf, logger: T, ) -> Result { - let logger = Arc::new(logger); - let mut logs: AsyncPerfEventArray<_> = bpf - .take_map(MAP_NAME) - .ok_or(Error::MapNotFound)? - .try_into()?; + let map = bpf.take_map(MAP_NAME).ok_or(Error::MapNotFound)?; + Self::read_logs_async(map, logger)?; + Ok(EbpfLogger {}) + } + + /// Attaches to an existing `aya-log-ebpf` log created by a running ebpf + /// program identified by `program_id`. The log records will be written + /// to the default logger. See [log::logger]. + /// It can be used to review the log for a pinned program after the user + /// application exits. + pub fn init_from_id(program_id: u32) -> Result { + Self::init_from_id_with_logger(program_id, log::logger()) + } + /// Attaches to an existing `aya-log-ebpf` log created by a running ebpf + /// program identified by `program_id`. The log records will be written + /// to the user provided logger. + /// It can be used to review the log for a pinned program after the user + /// application exits. + pub fn init_from_id_with_logger( + program_id: u32, + logger: T, + ) -> Result { + let program_info = loaded_programs() + .filter_map(|info| info.ok()) + .find(|info| info.id() == program_id) + .ok_or(Error::ProgramNotFound)?; + let map = program_info + .map_ids() + .map_err(Error::ProgramError)? + .iter() + .filter_map(|id| MapInfo::from_id(*id).ok()) + .find(|map_info| match map_info.name_as_str() { + Some(name) => name == MAP_NAME, + None => false, + }) + .ok_or(Error::MapNotFound)?; + let map = MapData::from_id(map.id()).map_err(Error::MapError)?; + + Self::read_logs_async(Map::PerfEventArray(map), logger)?; + + Ok(EbpfLogger {}) + } + + fn read_logs_async(map: Map, logger: T) -> Result<(), Error> { + let mut logs: AsyncPerfEventArray<_> = map.try_into()?; + + let logger = Arc::new(logger); for cpu_id in online_cpus().map_err(Error::InvalidOnlineCpu)? { let mut buf = logs.open(cpu_id, None)?; @@ -134,8 +178,7 @@ impl EbpfLogger { } }); } - - Ok(EbpfLogger {}) + Ok(()) } } @@ -374,6 +417,12 @@ pub enum Error { #[error("invalid /sys/devices/system/cpu/online format")] InvalidOnlineCpu(#[source] io::Error), + + #[error("program not found")] + ProgramNotFound, + + #[error(transparent)] + ProgramError(#[from] ProgramError), } fn log_buf(mut buf: &[u8], logger: &dyn Log) -> Result<(), ()> {