Browse Source

Merge pull request #900 from catalin-h/log_init_from_program_id

aya-log: allow re-attach and read previously created logs
Alessandro Decina 10 months ago
parent
commit
e5d107dd50
2 changed files with 61 additions and 8 deletions
  1. 55 8
      aya-log/src/lib.rs
  2. 6 0
      xtask/public-api/aya-log.txt

+ 55 - 8
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,52 @@ 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` instance.
+    ///
+    /// Attaches to the logs produced by `program_id`. Can be used to read logs generated by a
+    /// pinned program. The log records will be written to the default logger. See [log::logger].
+    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` instance and logs with the given logger.
+    ///
+    /// Attaches to the logs produced by `program_id`. Can be used to read logs generated by a
+    /// pinned program. The log records will be written to the given logger.
+    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 +176,7 @@ impl EbpfLogger {
                 }
             });
         }
-
-        Ok(EbpfLogger {})
+        Ok(())
     }
 }
 
@@ -374,6 +415,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<(), ()> {

+ 6 - 0
xtask/public-api/aya-log.txt

@@ -4,10 +4,14 @@ pub aya_log::Error::InvalidOnlineCpu(std::io::error::Error)
 pub aya_log::Error::MapError(aya::maps::MapError)
 pub aya_log::Error::MapNotFound
 pub aya_log::Error::PerfBufferError(aya::maps::perf::perf_buffer::PerfBufferError)
+pub aya_log::Error::ProgramError(aya::programs::ProgramError)
+pub aya_log::Error::ProgramNotFound
 impl core::convert::From<aya::maps::MapError> for aya_log::Error
 pub fn aya_log::Error::from(source: aya::maps::MapError) -> Self
 impl core::convert::From<aya::maps::perf::perf_buffer::PerfBufferError> for aya_log::Error
 pub fn aya_log::Error::from(source: aya::maps::perf::perf_buffer::PerfBufferError) -> Self
+impl core::convert::From<aya::programs::ProgramError> for aya_log::Error
+pub fn aya_log::Error::from(source: aya::programs::ProgramError) -> Self
 impl core::error::Error for aya_log::Error
 pub fn aya_log::Error::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
 impl core::fmt::Debug for aya_log::Error
@@ -66,6 +70,8 @@ pub fn aya_log::DefaultFormatter::from(t: T) -> T
 pub struct aya_log::EbpfLogger
 impl aya_log::EbpfLogger
 pub fn aya_log::EbpfLogger::init(bpf: &mut aya::bpf::Ebpf) -> core::result::Result<aya_log::EbpfLogger, aya_log::Error>
+pub fn aya_log::EbpfLogger::init_from_id(program_id: u32) -> core::result::Result<aya_log::EbpfLogger, aya_log::Error>
+pub fn aya_log::EbpfLogger::init_from_id_with_logger<T: log::Log + 'static>(program_id: u32, logger: T) -> core::result::Result<aya_log::EbpfLogger, aya_log::Error>
 pub fn aya_log::EbpfLogger::init_with_logger<T: log::Log + 'static>(bpf: &mut aya::bpf::Ebpf, logger: T) -> core::result::Result<aya_log::EbpfLogger, aya_log::Error>
 impl core::marker::Freeze for aya_log::EbpfLogger
 impl core::marker::Send for aya_log::EbpfLogger