aya-log: allow re-attach and read previously created logs

This feature is useful if someone wants to view the log contents
of a program that is already running. For e.g. a pinned program
or an XDP program attached to a net interface.
pull/900/head
Catalin Horghidan 7 months ago committed by Alessandro Decina
parent fc2eb70163
commit e66f9540c9

@ -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<EbpfLogger, Error> {
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<EbpfLogger, Error> {
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<T: Log + 'static>(
program_id: u32,
logger: T,
) -> Result<EbpfLogger, Error> {
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<T: Log + 'static>(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<(), ()> {

Loading…
Cancel
Save