Skip to content

Commit

Permalink
aya-log: allow re-attach and read previously created logs
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
catalin-h authored and alessandrod committed Apr 25, 2024
1 parent fc2eb70 commit e66f954
Showing 1 changed file with 57 additions and 8 deletions.
65 changes: 57 additions & 8 deletions aya-log/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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)?;

Expand All @@ -134,8 +178,7 @@ impl EbpfLogger {
}
});
}

Ok(EbpfLogger {})
Ok(())
}
}

Expand Down Expand Up @@ -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<(), ()> {
Expand Down

0 comments on commit e66f954

Please sign in to comment.