aya_log/
lib.rs

1//! A logging framework for eBPF programs.
2//!
3//! This is the user space side of the [Aya] logging framework. For the eBPF
4//! side, see the `aya-log-ebpf` crate.
5//!
6//! `aya-log` provides the [EbpfLogger] type, which reads log records created by
7//! `aya-log-ebpf` and logs them using the [log] crate. Any logger that
8//! implements the [Log] trait can be used with this crate.
9//!
10//! # Example:
11//!
12//! This example uses the [env_logger] crate to log messages to the terminal.
13//!
14//! ```no_run
15//! # let mut bpf = aya::Ebpf::load(&[]).unwrap();
16//! use aya_log::EbpfLogger;
17//!
18//! // initialize env_logger as the default logger
19//! env_logger::init();
20//!
21//! // start reading aya-log records and log them using the default logger
22//! EbpfLogger::init(&mut bpf).unwrap();
23//! ```
24//!
25//! With the following eBPF code:
26//!
27//! ```ignore
28//! # let ctx = ();
29//! use aya_log_ebpf::{debug, error, info, trace, warn};
30//!
31//! error!(&ctx, "this is an error message 🚨");
32//! warn!(&ctx, "this is a warning message ⚠ī¸");
33//! info!(&ctx, "this is an info message ℹī¸");
34//! debug!(&ctx, "this is a debug message ī¸đŸ");
35//! trace!(&ctx, "this is a trace message 🔍");
36//! ```
37//! Outputs:
38//!
39//! ```text
40//! 21:58:55 [ERROR] xxx: [src/main.rs:35] this is an error message 🚨
41//! 21:58:55 [WARN] xxx: [src/main.rs:36] this is a warning message ⚠ī¸
42//! 21:58:55 [INFO] xxx: [src/main.rs:37] this is an info message ℹī¸
43//! 21:58:55 [DEBUG] (7) xxx: [src/main.rs:38] this is a debug message ī¸đŸ
44//! 21:58:55 [TRACE] (7) xxx: [src/main.rs:39] this is a trace message 🔍
45//! ```
46//!
47//! [Aya]: https://docs.rs/aya
48//! [env_logger]: https://docs.rs/env_logger
49//! [Log]: https://docs.rs/log/0.4.14/log/trait.Log.html
50//! [log]: https://docs.rs/log
51//!
52use std::{
53    fmt::{LowerHex, UpperHex},
54    io, mem,
55    net::{Ipv4Addr, Ipv6Addr},
56    ptr, str,
57    sync::Arc,
58};
59
60const MAP_NAME: &str = "AYA_LOGS";
61
62use aya::{
63    maps::{
64        perf::{AsyncPerfEventArray, Events, PerfBufferError},
65        Map, MapData, MapError, MapInfo,
66    },
67    programs::{loaded_programs, ProgramError},
68    util::online_cpus,
69    Ebpf, Pod,
70};
71use aya_log_common::{
72    Argument, DisplayHint, Level, LogValueLength, RecordField, LOG_BUF_CAPACITY, LOG_FIELDS,
73};
74use bytes::BytesMut;
75use log::{error, Log, Record};
76use thiserror::Error;
77
78#[allow(dead_code)] // TODO(https://github.com/rust-lang/rust/issues/120770): Remove when false positive is fixed.
79#[derive(Copy, Clone)]
80#[repr(transparent)]
81struct RecordFieldWrapper(RecordField);
82#[allow(dead_code)] // TODO(https://github.com/rust-lang/rust/issues/120770): Remove when false positive is fixed.
83#[derive(Copy, Clone)]
84#[repr(transparent)]
85struct ArgumentWrapper(Argument);
86#[derive(Copy, Clone)]
87#[repr(transparent)]
88struct DisplayHintWrapper(DisplayHint);
89
90unsafe impl Pod for RecordFieldWrapper {}
91unsafe impl Pod for ArgumentWrapper {}
92unsafe impl Pod for DisplayHintWrapper {}
93
94/// Log messages generated by `aya_log_ebpf` using the [log] crate.
95///
96/// For more details see the [module level documentation](crate).
97pub struct EbpfLogger;
98
99/// Log messages generated by `aya_log_ebpf` using the [log] crate.
100#[deprecated(since = "0.2.1", note = "Use `aya_log::EbpfLogger` instead")]
101pub type BpfLogger = EbpfLogger;
102
103impl EbpfLogger {
104    /// Starts reading log records created with `aya-log-ebpf` and logs them
105    /// with the default logger. See [log::logger].
106    pub fn init(bpf: &mut Ebpf) -> Result<EbpfLogger, Error> {
107        EbpfLogger::init_with_logger(bpf, log::logger())
108    }
109
110    /// Starts reading log records created with `aya-log-ebpf` and logs them
111    /// with the given logger.
112    pub fn init_with_logger<T: Log + 'static>(
113        bpf: &mut Ebpf,
114        logger: T,
115    ) -> Result<EbpfLogger, Error> {
116        let map = bpf.take_map(MAP_NAME).ok_or(Error::MapNotFound)?;
117        Self::read_logs_async(map, logger)?;
118        Ok(EbpfLogger {})
119    }
120
121    /// Attaches to an existing `aya-log-ebpf` instance.
122    ///
123    /// Attaches to the logs produced by `program_id`. Can be used to read logs generated by a
124    /// pinned program. The log records will be written to the default logger. See [log::logger].
125    pub fn init_from_id(program_id: u32) -> Result<EbpfLogger, Error> {
126        Self::init_from_id_with_logger(program_id, log::logger())
127    }
128
129    /// Attaches to an existing `aya-log-ebpf` instance and logs with the given logger.
130    ///
131    /// Attaches to the logs produced by `program_id`. Can be used to read logs generated by a
132    /// pinned program. The log records will be written to the given logger.
133    pub fn init_from_id_with_logger<T: Log + 'static>(
134        program_id: u32,
135        logger: T,
136    ) -> Result<EbpfLogger, Error> {
137        let program_info = loaded_programs()
138            .filter_map(|info| info.ok())
139            .find(|info| info.id() == program_id)
140            .ok_or(Error::ProgramNotFound)?;
141
142        let map = program_info
143            .map_ids()
144            .map_err(Error::ProgramError)?
145            .ok_or_else(|| Error::MapNotFound)?
146            .iter()
147            .filter_map(|id| MapInfo::from_id(*id).ok())
148            .find(|map_info| match map_info.name_as_str() {
149                Some(name) => name == MAP_NAME,
150                None => false,
151            })
152            .ok_or(Error::MapNotFound)?;
153        let map = MapData::from_id(map.id()).map_err(Error::MapError)?;
154
155        Self::read_logs_async(Map::PerfEventArray(map), logger)?;
156
157        Ok(EbpfLogger {})
158    }
159
160    fn read_logs_async<T: Log + 'static>(map: Map, logger: T) -> Result<(), Error> {
161        let mut logs: AsyncPerfEventArray<_> = map.try_into()?;
162
163        let logger = Arc::new(logger);
164        for cpu_id in online_cpus().map_err(|(_, error)| Error::InvalidOnlineCpu(error))? {
165            let mut buf = logs.open(cpu_id, None)?;
166
167            let log = logger.clone();
168            tokio::spawn(async move {
169                let mut buffers = vec![BytesMut::with_capacity(LOG_BUF_CAPACITY); 10];
170
171                loop {
172                    let Events { read, lost: _ } = buf.read_events(&mut buffers).await.unwrap();
173
174                    for buf in buffers.iter().take(read) {
175                        log_buf(buf.as_ref(), &*log).unwrap();
176                    }
177                }
178            });
179        }
180        Ok(())
181    }
182}
183
184pub trait Formatter<T> {
185    fn format(v: T) -> String;
186}
187
188pub struct DefaultFormatter;
189impl<T> Formatter<T> for DefaultFormatter
190where
191    T: ToString,
192{
193    fn format(v: T) -> String {
194        v.to_string()
195    }
196}
197
198pub struct LowerHexFormatter;
199impl<T> Formatter<T> for LowerHexFormatter
200where
201    T: LowerHex,
202{
203    fn format(v: T) -> String {
204        format!("{v:x}")
205    }
206}
207
208pub struct LowerHexBytesFormatter;
209impl Formatter<&[u8]> for LowerHexBytesFormatter {
210    fn format(v: &[u8]) -> String {
211        let mut s = String::new();
212        for v in v {
213            let () = core::fmt::write(&mut s, format_args!("{v:02x}")).unwrap();
214        }
215        s
216    }
217}
218
219pub struct UpperHexFormatter;
220impl<T> Formatter<T> for UpperHexFormatter
221where
222    T: UpperHex,
223{
224    fn format(v: T) -> String {
225        format!("{v:X}")
226    }
227}
228
229pub struct UpperHexBytesFormatter;
230impl Formatter<&[u8]> for UpperHexBytesFormatter {
231    fn format(v: &[u8]) -> String {
232        let mut s = String::new();
233        for v in v {
234            let () = core::fmt::write(&mut s, format_args!("{v:02X}")).unwrap();
235        }
236        s
237    }
238}
239
240pub struct Ipv4Formatter;
241impl<T> Formatter<T> for Ipv4Formatter
242where
243    T: Into<Ipv4Addr>,
244{
245    fn format(v: T) -> String {
246        v.into().to_string()
247    }
248}
249
250pub struct Ipv6Formatter;
251impl<T> Formatter<T> for Ipv6Formatter
252where
253    T: Into<Ipv6Addr>,
254{
255    fn format(v: T) -> String {
256        v.into().to_string()
257    }
258}
259
260pub struct LowerMacFormatter;
261impl Formatter<[u8; 6]> for LowerMacFormatter {
262    fn format(v: [u8; 6]) -> String {
263        format!(
264            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
265            v[0], v[1], v[2], v[3], v[4], v[5]
266        )
267    }
268}
269
270pub struct UpperMacFormatter;
271impl Formatter<[u8; 6]> for UpperMacFormatter {
272    fn format(v: [u8; 6]) -> String {
273        format!(
274            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
275            v[0], v[1], v[2], v[3], v[4], v[5]
276        )
277    }
278}
279
280trait Format {
281    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()>;
282}
283
284impl Format for &[u8] {
285    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
286        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
287            Some(DisplayHint::LowerHex) => Ok(LowerHexBytesFormatter::format(self)),
288            Some(DisplayHint::UpperHex) => Ok(UpperHexBytesFormatter::format(self)),
289            _ => Err(()),
290        }
291    }
292}
293
294impl Format for u32 {
295    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
296        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
297            Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
298            Some(DisplayHint::LowerHex) => Ok(LowerHexFormatter::format(self)),
299            Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)),
300            Some(DisplayHint::Ip) => Ok(Ipv4Formatter::format(*self)),
301            Some(DisplayHint::LowerMac) => Err(()),
302            Some(DisplayHint::UpperMac) => Err(()),
303            _ => Ok(DefaultFormatter::format(self)),
304        }
305    }
306}
307
308impl Format for Ipv4Addr {
309    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
310        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
311            Some(DisplayHint::Default) => Ok(Ipv4Formatter::format(*self)),
312            Some(DisplayHint::LowerHex) => Err(()),
313            Some(DisplayHint::UpperHex) => Err(()),
314            Some(DisplayHint::Ip) => Ok(Ipv4Formatter::format(*self)),
315            Some(DisplayHint::LowerMac) => Err(()),
316            Some(DisplayHint::UpperMac) => Err(()),
317            None => Ok(Ipv4Formatter::format(*self)),
318        }
319    }
320}
321
322impl Format for Ipv6Addr {
323    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
324        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
325            Some(DisplayHint::Default) => Ok(Ipv6Formatter::format(*self)),
326            Some(DisplayHint::LowerHex) => Err(()),
327            Some(DisplayHint::UpperHex) => Err(()),
328            Some(DisplayHint::Ip) => Ok(Ipv6Formatter::format(*self)),
329            Some(DisplayHint::LowerMac) => Err(()),
330            Some(DisplayHint::UpperMac) => Err(()),
331            None => Ok(Ipv6Formatter::format(*self)),
332        }
333    }
334}
335
336impl Format for [u8; 4] {
337    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
338        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
339            Some(DisplayHint::Default) => Ok(Ipv4Formatter::format(*self)),
340            Some(DisplayHint::LowerHex) => Err(()),
341            Some(DisplayHint::UpperHex) => Err(()),
342            Some(DisplayHint::Ip) => Ok(Ipv4Formatter::format(*self)),
343            Some(DisplayHint::LowerMac) => Err(()),
344            Some(DisplayHint::UpperMac) => Err(()),
345            None => Ok(Ipv4Formatter::format(*self)),
346        }
347    }
348}
349
350impl Format for [u8; 6] {
351    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
352        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
353            Some(DisplayHint::Default) => Err(()),
354            Some(DisplayHint::LowerHex) => Err(()),
355            Some(DisplayHint::UpperHex) => Err(()),
356            Some(DisplayHint::Ip) => Err(()),
357            Some(DisplayHint::LowerMac) => Ok(LowerMacFormatter::format(*self)),
358            Some(DisplayHint::UpperMac) => Ok(UpperMacFormatter::format(*self)),
359            _ => Err(()),
360        }
361    }
362}
363
364impl Format for [u8; 16] {
365    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
366        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
367            Some(DisplayHint::Default) => Err(()),
368            Some(DisplayHint::LowerHex) => Err(()),
369            Some(DisplayHint::UpperHex) => Err(()),
370            Some(DisplayHint::Ip) => Ok(Ipv6Formatter::format(*self)),
371            Some(DisplayHint::LowerMac) => Err(()),
372            Some(DisplayHint::UpperMac) => Err(()),
373            _ => Err(()),
374        }
375    }
376}
377
378impl Format for [u16; 8] {
379    fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
380        match last_hint.map(|DisplayHintWrapper(dh)| dh) {
381            Some(DisplayHint::Default) => Err(()),
382            Some(DisplayHint::LowerHex) => Err(()),
383            Some(DisplayHint::UpperHex) => Err(()),
384            Some(DisplayHint::Ip) => Ok(Ipv6Formatter::format(*self)),
385            Some(DisplayHint::LowerMac) => Err(()),
386            Some(DisplayHint::UpperMac) => Err(()),
387            _ => Err(()),
388        }
389    }
390}
391
392macro_rules! impl_format {
393    ($type:ident) => {
394        impl Format for $type {
395            fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
396                match last_hint.map(|DisplayHintWrapper(dh)| dh) {
397                    Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
398                    Some(DisplayHint::LowerHex) => Ok(LowerHexFormatter::format(self)),
399                    Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)),
400                    Some(DisplayHint::Ip) => Err(()),
401                    Some(DisplayHint::LowerMac) => Err(()),
402                    Some(DisplayHint::UpperMac) => Err(()),
403                    _ => Ok(DefaultFormatter::format(self)),
404                }
405            }
406        }
407    };
408}
409
410impl_format!(i8);
411impl_format!(i16);
412impl_format!(i32);
413impl_format!(i64);
414impl_format!(isize);
415
416impl_format!(u8);
417impl_format!(u16);
418impl_format!(u64);
419impl_format!(usize);
420
421macro_rules! impl_format_float {
422    ($type:ident) => {
423        impl Format for $type {
424            fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
425                match last_hint.map(|DisplayHintWrapper(dh)| dh) {
426                    Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
427                    Some(DisplayHint::LowerHex) => Err(()),
428                    Some(DisplayHint::UpperHex) => Err(()),
429                    Some(DisplayHint::Ip) => Err(()),
430                    Some(DisplayHint::LowerMac) => Err(()),
431                    Some(DisplayHint::UpperMac) => Err(()),
432                    _ => Ok(DefaultFormatter::format(self)),
433                }
434            }
435        }
436    };
437}
438
439impl_format_float!(f32);
440impl_format_float!(f64);
441
442#[derive(Error, Debug)]
443pub enum Error {
444    #[error("log event array {} doesn't exist", MAP_NAME)]
445    MapNotFound,
446
447    #[error("error opening log event array")]
448    MapError(#[from] MapError),
449
450    #[error("error opening log buffer")]
451    PerfBufferError(#[from] PerfBufferError),
452
453    #[error("invalid /sys/devices/system/cpu/online format")]
454    InvalidOnlineCpu(#[source] io::Error),
455
456    #[error("program not found")]
457    ProgramNotFound,
458
459    #[error(transparent)]
460    ProgramError(#[from] ProgramError),
461}
462
463fn log_buf(mut buf: &[u8], logger: &dyn Log) -> Result<(), ()> {
464    let mut target = None;
465    let mut level = None;
466    let mut module = None;
467    let mut file = None;
468    let mut line = None;
469    let mut num_args = None;
470
471    for _ in 0..LOG_FIELDS {
472        let (RecordFieldWrapper(tag), value, rest) = try_read(buf)?;
473
474        match tag {
475            RecordField::Target => {
476                target = Some(str::from_utf8(value).map_err(|_| ())?);
477            }
478            RecordField::Level => {
479                level = Some({
480                    let level = unsafe { ptr::read_unaligned(value.as_ptr() as *const _) };
481                    match level {
482                        Level::Error => log::Level::Error,
483                        Level::Warn => log::Level::Warn,
484                        Level::Info => log::Level::Info,
485                        Level::Debug => log::Level::Debug,
486                        Level::Trace => log::Level::Trace,
487                    }
488                })
489            }
490            RecordField::Module => {
491                module = Some(str::from_utf8(value).map_err(|_| ())?);
492            }
493            RecordField::File => {
494                file = Some(str::from_utf8(value).map_err(|_| ())?);
495            }
496            RecordField::Line => {
497                line = Some(u32::from_ne_bytes(value.try_into().map_err(|_| ())?));
498            }
499            RecordField::NumArgs => {
500                num_args = Some(usize::from_ne_bytes(value.try_into().map_err(|_| ())?));
501            }
502        }
503
504        buf = rest;
505    }
506
507    let mut full_log_msg = String::new();
508    let mut last_hint: Option<DisplayHintWrapper> = None;
509    for _ in 0..num_args.ok_or(())? {
510        let (ArgumentWrapper(tag), value, rest) = try_read(buf)?;
511
512        match tag {
513            Argument::DisplayHint => {
514                last_hint = Some(unsafe { ptr::read_unaligned(value.as_ptr() as *const _) });
515            }
516            Argument::I8 => {
517                full_log_msg.push_str(
518                    &i8::from_ne_bytes(value.try_into().map_err(|_| ())?)
519                        .format(last_hint.take())?,
520                );
521            }
522            Argument::I16 => {
523                full_log_msg.push_str(
524                    &i16::from_ne_bytes(value.try_into().map_err(|_| ())?)
525                        .format(last_hint.take())?,
526                );
527            }
528            Argument::I32 => {
529                full_log_msg.push_str(
530                    &i32::from_ne_bytes(value.try_into().map_err(|_| ())?)
531                        .format(last_hint.take())?,
532                );
533            }
534            Argument::I64 => {
535                full_log_msg.push_str(
536                    &i64::from_ne_bytes(value.try_into().map_err(|_| ())?)
537                        .format(last_hint.take())?,
538                );
539            }
540            Argument::Isize => {
541                full_log_msg.push_str(
542                    &isize::from_ne_bytes(value.try_into().map_err(|_| ())?)
543                        .format(last_hint.take())?,
544                );
545            }
546            Argument::U8 => {
547                full_log_msg.push_str(
548                    &u8::from_ne_bytes(value.try_into().map_err(|_| ())?)
549                        .format(last_hint.take())?,
550                );
551            }
552            Argument::U16 => {
553                full_log_msg.push_str(
554                    &u16::from_ne_bytes(value.try_into().map_err(|_| ())?)
555                        .format(last_hint.take())?,
556                );
557            }
558            Argument::U32 => {
559                full_log_msg.push_str(
560                    &u32::from_ne_bytes(value.try_into().map_err(|_| ())?)
561                        .format(last_hint.take())?,
562                );
563            }
564            Argument::U64 => {
565                full_log_msg.push_str(
566                    &u64::from_ne_bytes(value.try_into().map_err(|_| ())?)
567                        .format(last_hint.take())?,
568                );
569            }
570            Argument::Usize => {
571                full_log_msg.push_str(
572                    &usize::from_ne_bytes(value.try_into().map_err(|_| ())?)
573                        .format(last_hint.take())?,
574                );
575            }
576            Argument::F32 => {
577                full_log_msg.push_str(
578                    &f32::from_ne_bytes(value.try_into().map_err(|_| ())?)
579                        .format(last_hint.take())?,
580                );
581            }
582            Argument::F64 => {
583                full_log_msg.push_str(
584                    &f64::from_ne_bytes(value.try_into().map_err(|_| ())?)
585                        .format(last_hint.take())?,
586                );
587            }
588            Argument::Ipv4Addr => {
589                let value: [u8; 4] = value.try_into().map_err(|_| ())?;
590                let value = Ipv4Addr::from(value);
591                full_log_msg.push_str(&value.format(last_hint.take())?)
592            }
593            Argument::Ipv6Addr => {
594                let value: [u8; 16] = value.try_into().map_err(|_| ())?;
595                let value = Ipv6Addr::from(value);
596                full_log_msg.push_str(&value.format(last_hint.take())?)
597            }
598            Argument::ArrU8Len4 => {
599                let value: [u8; 4] = value.try_into().map_err(|_| ())?;
600                full_log_msg.push_str(&value.format(last_hint.take())?);
601            }
602            Argument::ArrU8Len6 => {
603                let value: [u8; 6] = value.try_into().map_err(|_| ())?;
604                full_log_msg.push_str(&value.format(last_hint.take())?);
605            }
606            Argument::ArrU8Len16 => {
607                let value: [u8; 16] = value.try_into().map_err(|_| ())?;
608                full_log_msg.push_str(&value.format(last_hint.take())?);
609            }
610            Argument::ArrU16Len8 => {
611                let data: [u8; 16] = value.try_into().map_err(|_| ())?;
612                let mut value: [u16; 8] = Default::default();
613                for (i, s) in data.chunks_exact(2).enumerate() {
614                    value[i] = ((s[1] as u16) << 8) | s[0] as u16;
615                }
616                full_log_msg.push_str(&value.format(last_hint.take())?);
617            }
618            Argument::Bytes => {
619                full_log_msg.push_str(&value.format(last_hint.take())?);
620            }
621            Argument::Str => match str::from_utf8(value) {
622                Ok(v) => {
623                    full_log_msg.push_str(v);
624                }
625                Err(e) => error!("received invalid utf8 string: {}", e),
626            },
627        }
628
629        buf = rest;
630    }
631
632    logger.log(
633        &Record::builder()
634            .args(format_args!("{full_log_msg}"))
635            .target(target.ok_or(())?)
636            .level(level.ok_or(())?)
637            .module_path(module)
638            .file(file)
639            .line(line)
640            .build(),
641    );
642    logger.flush();
643    Ok(())
644}
645
646fn try_read<T: Pod>(mut buf: &[u8]) -> Result<(T, &[u8], &[u8]), ()> {
647    if buf.len() < mem::size_of::<T>() + mem::size_of::<LogValueLength>() {
648        return Err(());
649    }
650
651    let tag = unsafe { ptr::read_unaligned(buf.as_ptr() as *const T) };
652    buf = &buf[mem::size_of::<T>()..];
653
654    let len =
655        LogValueLength::from_ne_bytes(buf[..mem::size_of::<LogValueLength>()].try_into().unwrap());
656    buf = &buf[mem::size_of::<LogValueLength>()..];
657
658    let len: usize = len.into();
659    if buf.len() < len {
660        return Err(());
661    }
662
663    let (value, rest) = buf.split_at(len);
664    Ok((tag, value, rest))
665}
666
667#[cfg(test)]
668mod test {
669    use std::net::IpAddr;
670
671    use aya_log_common::{write_record_header, WriteToBuf};
672    use log::{logger, Level};
673
674    use super::*;
675
676    fn new_log(args: usize) -> Option<(usize, Vec<u8>)> {
677        let mut buf = vec![0; 8192];
678        let len = write_record_header(
679            &mut buf,
680            "test",
681            aya_log_common::Level::Info,
682            "test",
683            "test.rs",
684            123,
685            args,
686        )?;
687        Some((len.get(), buf))
688    }
689
690    #[test]
691    fn test_str() {
692        testing_logger::setup();
693        let (mut len, mut input) = new_log(1).unwrap();
694
695        len += "test".write(&mut input[len..]).unwrap().get();
696
697        _ = len;
698
699        let logger = logger();
700        let () = log_buf(&input, logger).unwrap();
701        testing_logger::validate(|captured_logs| {
702            assert_eq!(captured_logs.len(), 1);
703            assert_eq!(captured_logs[0].body, "test");
704            assert_eq!(captured_logs[0].level, Level::Info);
705        });
706    }
707
708    #[test]
709    fn test_str_with_args() {
710        testing_logger::setup();
711        let (mut len, mut input) = new_log(2).unwrap();
712
713        len += "hello ".write(&mut input[len..]).unwrap().get();
714        len += "test".write(&mut input[len..]).unwrap().get();
715
716        _ = len;
717
718        let logger = logger();
719        let () = log_buf(&input, logger).unwrap();
720        testing_logger::validate(|captured_logs| {
721            assert_eq!(captured_logs.len(), 1);
722            assert_eq!(captured_logs[0].body, "hello test");
723            assert_eq!(captured_logs[0].level, Level::Info);
724        });
725    }
726
727    #[test]
728    fn test_bytes() {
729        testing_logger::setup();
730        let (mut len, mut input) = new_log(2).unwrap();
731
732        len += DisplayHint::LowerHex
733            .write(&mut input[len..])
734            .unwrap()
735            .get();
736        len += [0xde, 0xad].write(&mut input[len..]).unwrap().get();
737
738        _ = len;
739
740        let logger = logger();
741        let () = log_buf(&input, logger).unwrap();
742        testing_logger::validate(|captured_logs| {
743            assert_eq!(captured_logs.len(), 1);
744            assert_eq!(captured_logs[0].body, "dead");
745            assert_eq!(captured_logs[0].level, Level::Info);
746        });
747    }
748
749    #[test]
750    fn test_bytes_with_args() {
751        testing_logger::setup();
752        let (mut len, mut input) = new_log(5).unwrap();
753
754        len += DisplayHint::LowerHex
755            .write(&mut input[len..])
756            .unwrap()
757            .get();
758        len += [0xde, 0xad].write(&mut input[len..]).unwrap().get();
759
760        len += " ".write(&mut input[len..]).unwrap().get();
761
762        len += DisplayHint::UpperHex
763            .write(&mut input[len..])
764            .unwrap()
765            .get();
766        len += [0xbe, 0xef].write(&mut input[len..]).unwrap().get();
767
768        _ = len;
769
770        let logger = logger();
771        let () = log_buf(&input, logger).unwrap();
772        testing_logger::validate(|captured_logs| {
773            assert_eq!(captured_logs.len(), 1);
774            assert_eq!(captured_logs[0].body, "dead BEEF");
775            assert_eq!(captured_logs[0].level, Level::Info);
776        });
777    }
778
779    #[test]
780    fn test_bytes_unambiguous() {
781        testing_logger::setup();
782        let (mut len, mut input) = new_log(5).unwrap();
783
784        len += DisplayHint::LowerHex
785            .write(&mut input[len..])
786            .unwrap()
787            .get();
788        len += [0x01, 0x02].write(&mut input[len..]).unwrap().get();
789
790        len += " ".write(&mut input[len..]).unwrap().get();
791
792        len += DisplayHint::LowerHex
793            .write(&mut input[len..])
794            .unwrap()
795            .get();
796        len += [0x12].write(&mut input[len..]).unwrap().get();
797
798        _ = len;
799
800        let logger = logger();
801        let () = log_buf(&input, logger).unwrap();
802        testing_logger::validate(|captured_logs| {
803            assert_eq!(captured_logs.len(), 1);
804            assert_eq!(captured_logs[0].body, "0102 12");
805            assert_eq!(captured_logs[0].level, Level::Info);
806        });
807    }
808
809    #[test]
810    fn test_display_hint_default() {
811        testing_logger::setup();
812        let (mut len, mut input) = new_log(3).unwrap();
813
814        len += "default hint: ".write(&mut input[len..]).unwrap().get();
815        len += DisplayHint::Default.write(&mut input[len..]).unwrap().get();
816        len += 14.write(&mut input[len..]).unwrap().get();
817
818        _ = len;
819
820        let logger = logger();
821        let () = log_buf(&input, logger).unwrap();
822        testing_logger::validate(|captured_logs| {
823            assert_eq!(captured_logs.len(), 1);
824            assert_eq!(captured_logs[0].body, "default hint: 14");
825            assert_eq!(captured_logs[0].level, Level::Info);
826        });
827    }
828
829    #[test]
830    fn test_display_hint_lower_hex() {
831        testing_logger::setup();
832        let (mut len, mut input) = new_log(3).unwrap();
833
834        len += "lower hex: ".write(&mut input[len..]).unwrap().get();
835        len += DisplayHint::LowerHex
836            .write(&mut input[len..])
837            .unwrap()
838            .get();
839        len += 200.write(&mut input[len..]).unwrap().get();
840
841        _ = len;
842
843        let logger = logger();
844        let () = log_buf(&input, logger).unwrap();
845        testing_logger::validate(|captured_logs| {
846            assert_eq!(captured_logs.len(), 1);
847            assert_eq!(captured_logs[0].body, "lower hex: c8");
848            assert_eq!(captured_logs[0].level, Level::Info);
849        });
850    }
851
852    #[test]
853    fn test_display_hint_upper_hex() {
854        testing_logger::setup();
855        let (mut len, mut input) = new_log(3).unwrap();
856
857        len += "upper hex: ".write(&mut input[len..]).unwrap().get();
858        len += DisplayHint::UpperHex
859            .write(&mut input[len..])
860            .unwrap()
861            .get();
862        len += 200.write(&mut input[len..]).unwrap().get();
863
864        _ = len;
865
866        let logger = logger();
867        let () = log_buf(&input, logger).unwrap();
868        testing_logger::validate(|captured_logs| {
869            assert_eq!(captured_logs.len(), 1);
870            assert_eq!(captured_logs[0].body, "upper hex: C8");
871            assert_eq!(captured_logs[0].level, Level::Info);
872        });
873    }
874
875    #[test]
876    fn test_display_hint_ipv4() {
877        testing_logger::setup();
878        let (mut len, mut input) = new_log(3).unwrap();
879
880        len += "ipv4: ".write(&mut input[len..]).unwrap().get();
881        len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
882        len += Ipv4Addr::new(10, 0, 0, 1)
883            .write(&mut input[len..])
884            .unwrap()
885            .get();
886
887        _ = len;
888
889        let logger = logger();
890        let () = log_buf(&input, logger).unwrap();
891        testing_logger::validate(|captured_logs| {
892            assert_eq!(captured_logs.len(), 1);
893            assert_eq!(captured_logs[0].body, "ipv4: 10.0.0.1");
894            assert_eq!(captured_logs[0].level, Level::Info);
895        });
896    }
897
898    #[test]
899    fn test_display_hint_ip_ipv4() {
900        testing_logger::setup();
901        let (mut len, mut input) = new_log(3).unwrap();
902
903        len += "ipv4: ".write(&mut input[len..]).unwrap().get();
904        len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
905        len += IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))
906            .write(&mut input[len..])
907            .unwrap()
908            .get();
909
910        _ = len;
911
912        let logger = logger();
913        let () = log_buf(&input, logger).unwrap();
914        testing_logger::validate(|captured_logs| {
915            assert_eq!(captured_logs.len(), 1);
916            assert_eq!(captured_logs[0].body, "ipv4: 10.0.0.1");
917            assert_eq!(captured_logs[0].level, Level::Info);
918        });
919    }
920
921    #[test]
922    fn test_display_hint_ipv4_u32() {
923        testing_logger::setup();
924        let (mut len, mut input) = new_log(3).unwrap();
925
926        len += "ipv4: ".write(&mut input[len..]).unwrap().get();
927        len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
928        // 10.0.0.1 as u32
929        len += 167772161u32.write(&mut input[len..]).unwrap().get();
930
931        _ = len;
932
933        let logger = logger();
934        let () = log_buf(&input, logger).unwrap();
935        testing_logger::validate(|captured_logs| {
936            assert_eq!(captured_logs.len(), 1);
937            assert_eq!(captured_logs[0].body, "ipv4: 10.0.0.1");
938            assert_eq!(captured_logs[0].level, Level::Info);
939        });
940    }
941
942    #[test]
943    fn test_display_hint_ipv6() {
944        testing_logger::setup();
945        let (mut len, mut input) = new_log(3).unwrap();
946
947        len += "ipv6: ".write(&mut input[len..]).unwrap().get();
948        len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
949        len += Ipv6Addr::new(
950            0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001,
951        )
952        .write(&mut input[len..])
953        .unwrap()
954        .get();
955
956        _ = len;
957
958        let logger = logger();
959        let () = log_buf(&input, logger).unwrap();
960        testing_logger::validate(|captured_logs| {
961            assert_eq!(captured_logs.len(), 1);
962            assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
963            assert_eq!(captured_logs[0].level, Level::Info);
964        });
965    }
966
967    #[test]
968    fn test_display_hint_ip_ipv6() {
969        testing_logger::setup();
970        let (mut len, mut input) = new_log(3).unwrap();
971
972        len += "ipv6: ".write(&mut input[len..]).unwrap().get();
973        len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
974        len += IpAddr::V6(Ipv6Addr::new(
975            0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001,
976        ))
977        .write(&mut input[len..])
978        .unwrap()
979        .get();
980
981        _ = len;
982
983        let logger = logger();
984        let () = log_buf(&input, logger).unwrap();
985        testing_logger::validate(|captured_logs| {
986            assert_eq!(captured_logs.len(), 1);
987            assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
988            assert_eq!(captured_logs[0].level, Level::Info);
989        });
990    }
991
992    #[test]
993    fn test_display_hint_ipv6_arr_u8_len_16() {
994        testing_logger::setup();
995        let (mut len, mut input) = new_log(3).unwrap();
996
997        len += "ipv6: ".write(&mut input[len..]).unwrap().get();
998        len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
999        // 2001:db8::1:1 as byte array
1000        let ipv6_arr: [u8; 16] = [
1001            0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1002            0x00, 0x01,
1003        ];
1004        len += ipv6_arr.write(&mut input[len..]).unwrap().get();
1005
1006        _ = len;
1007
1008        let logger = logger();
1009        let () = log_buf(&input, logger).unwrap();
1010        testing_logger::validate(|captured_logs| {
1011            assert_eq!(captured_logs.len(), 1);
1012            assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
1013            assert_eq!(captured_logs[0].level, Level::Info);
1014        });
1015    }
1016
1017    #[test]
1018    fn test_display_hint_ipv6_arr_u16_len_8() {
1019        testing_logger::setup();
1020        let (mut len, mut input) = new_log(3).unwrap();
1021
1022        len += "ipv6: ".write(&mut input[len..]).unwrap().get();
1023        len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1024        // 2001:db8::1:1 as u16 array
1025        #[cfg(target_endian = "little")]
1026        let ipv6_arr: [u16; 8] = [
1027            0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001,
1028        ];
1029        #[cfg(target_endian = "big")]
1030        let ipv6_arr: [u16; 8] = [
1031            0x0120, 0xb80d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0100,
1032        ];
1033        len += ipv6_arr.write(&mut input[len..]).unwrap().get();
1034
1035        _ = len;
1036
1037        let logger = logger();
1038        let () = log_buf(&input, logger).unwrap();
1039        testing_logger::validate(|captured_logs| {
1040            assert_eq!(captured_logs.len(), 1);
1041            assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
1042            assert_eq!(captured_logs[0].level, Level::Info);
1043        });
1044    }
1045
1046    #[test]
1047    fn test_display_hint_lower_mac() {
1048        testing_logger::setup();
1049        let (mut len, mut input) = new_log(3).unwrap();
1050
1051        len += "mac: ".write(&mut input[len..]).unwrap().get();
1052        len += DisplayHint::LowerMac
1053            .write(&mut input[len..])
1054            .unwrap()
1055            .get();
1056        // 00:00:5e:00:53:af as byte array
1057        let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf];
1058        len += mac_arr.write(&mut input[len..]).unwrap().get();
1059
1060        _ = len;
1061
1062        let logger = logger();
1063        let () = log_buf(&input, logger).unwrap();
1064        testing_logger::validate(|captured_logs| {
1065            assert_eq!(captured_logs.len(), 1);
1066            assert_eq!(captured_logs[0].body, "mac: 00:00:5e:00:53:af");
1067            assert_eq!(captured_logs[0].level, Level::Info);
1068        });
1069    }
1070
1071    #[test]
1072    fn test_display_hint_upper_mac() {
1073        testing_logger::setup();
1074        let (mut len, mut input) = new_log(3).unwrap();
1075
1076        len += "mac: ".write(&mut input[len..]).unwrap().get();
1077        len += DisplayHint::UpperMac
1078            .write(&mut input[len..])
1079            .unwrap()
1080            .get();
1081        // 00:00:5E:00:53:AF as byte array
1082        let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf];
1083        len += mac_arr.write(&mut input[len..]).unwrap().get();
1084
1085        _ = len;
1086
1087        let logger = logger();
1088        let () = log_buf(&input, logger).unwrap();
1089        testing_logger::validate(|captured_logs| {
1090            assert_eq!(captured_logs.len(), 1);
1091            assert_eq!(captured_logs[0].body, "mac: 00:00:5E:00:53:AF");
1092            assert_eq!(captured_logs[0].level, Level::Info);
1093        });
1094    }
1095}