1#![cfg_attr(test, expect(unused_crate_dependencies, reason = "used in doctests"))]
61
62use std::{
63 fmt::{LowerHex, UpperHex},
64 net::{Ipv4Addr, Ipv6Addr},
65 os::fd::{AsFd, AsRawFd},
66 ptr, str,
67};
68
69const MAP_NAME: &str = "AYA_LOGS";
70
71pub const LEVEL: &str = "AYA_LOG_LEVEL";
72use aya::{
73 Ebpf, Pod,
74 maps::{Map, MapData, MapError, MapInfo, RingBuf},
75 programs::{ProgramError, loaded_programs},
76};
77pub use aya_log_common::Level;
78use aya_log_common::{ArgumentKind, DisplayHint, LogValueLength, RecordFieldKind};
79use log::{Log, Record, error};
80use thiserror::Error;
81
82#[derive(Copy, Clone)]
83#[repr(transparent)]
84struct RecordFieldWrapper(RecordFieldKind);
85#[derive(Copy, Clone)]
86#[repr(transparent)]
87struct ArgumentWrapper(ArgumentKind);
88#[derive(Copy, Clone)]
89#[repr(transparent)]
90struct DisplayHintWrapper(DisplayHint);
91
92unsafe impl Pod for RecordFieldWrapper {}
93unsafe impl Pod for ArgumentWrapper {}
94unsafe impl Pod for DisplayHintWrapper {}
95
96#[must_use = "Dropping the logger will close the map FD and cause program loading failure."]
100pub struct EbpfLogger<T> {
101 ring_buf: RingBuf<MapData>,
102 logger: T,
103}
104
105impl<T> AsFd for EbpfLogger<T> {
106 fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
107 let Self {
108 ring_buf,
109 logger: _,
110 } = self;
111 ring_buf.as_fd()
112 }
113}
114
115impl<T> AsRawFd for EbpfLogger<T> {
116 fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd {
117 let Self {
118 ring_buf,
119 logger: _,
120 } = self;
121 ring_buf.as_raw_fd()
122 }
123}
124
125#[deprecated(since = "0.2.1", note = "Use `aya_log::EbpfLogger` instead")]
127pub type BpfLogger<T> = EbpfLogger<T>;
128
129impl EbpfLogger<&'static dyn Log> {
130 pub fn init(bpf: &mut Ebpf) -> Result<Self, Error> {
133 Self::init_with_logger(bpf, log::logger())
134 }
135
136 pub fn init_from_id(program_id: u32) -> Result<Self, Error> {
142 Self::init_from_id_with_logger(program_id, log::logger())
143 }
144}
145
146impl<T: Log> EbpfLogger<T> {
147 pub fn init_with_logger(bpf: &mut Ebpf, logger: T) -> Result<Self, Error> {
150 let map = bpf.take_map(MAP_NAME).ok_or(Error::MapNotFound)?;
151 Self::new(map, logger)
152 }
153
154 pub fn init_from_id_with_logger(program_id: u32, logger: T) -> Result<Self, Error> {
159 let program_info = loaded_programs()
160 .filter_map(Result::ok)
161 .find(|info| info.id() == program_id)
162 .ok_or(Error::ProgramNotFound)?;
163
164 let map = program_info
165 .map_ids()?
166 .ok_or_else(|| Error::MapNotFound)?
167 .iter()
168 .filter_map(|id| MapInfo::from_id(*id).ok())
169 .find(|map_info| map_info.name_as_str() == Some(MAP_NAME))
170 .ok_or(Error::MapNotFound)?;
171 let map = MapData::from_id(map.id())?;
172
173 Self::new(Map::RingBuf(map), logger)
174 }
175
176 fn new(map: Map, logger: T) -> Result<Self, Error> {
177 let ring_buf: RingBuf<_> = map.try_into()?;
178
179 Ok(Self { ring_buf, logger })
180 }
181
182 pub fn flush(&mut self) {
184 let Self { ring_buf, logger } = self;
185 while let Some(buf) = ring_buf.next() {
186 log_buf(buf.as_ref(), logger).unwrap();
187 }
188 }
189}
190
191pub trait Formatter<T> {
192 fn format(v: T) -> String;
193}
194
195pub struct DefaultFormatter;
196impl<T> Formatter<T> for DefaultFormatter
197where
198 T: ToString,
199{
200 fn format(v: T) -> String {
201 v.to_string()
202 }
203}
204
205pub struct LowerHexFormatter;
206impl<T> Formatter<T> for LowerHexFormatter
207where
208 T: LowerHex,
209{
210 fn format(v: T) -> String {
211 format!("{v:x}")
212 }
213}
214
215pub struct LowerHexBytesFormatter;
216impl Formatter<&[u8]> for LowerHexBytesFormatter {
217 fn format(v: &[u8]) -> String {
218 let mut s = String::new();
219 for v in v {
220 let () = core::fmt::write(&mut s, format_args!("{v:02x}")).unwrap();
221 }
222 s
223 }
224}
225
226pub struct UpperHexFormatter;
227impl<T> Formatter<T> for UpperHexFormatter
228where
229 T: UpperHex,
230{
231 fn format(v: T) -> String {
232 format!("{v:X}")
233 }
234}
235
236pub struct UpperHexBytesFormatter;
237impl Formatter<&[u8]> for UpperHexBytesFormatter {
238 fn format(v: &[u8]) -> String {
239 let mut s = String::new();
240 for v in v {
241 let () = core::fmt::write(&mut s, format_args!("{v:02X}")).unwrap();
242 }
243 s
244 }
245}
246
247pub struct Ipv4Formatter;
248impl<T> Formatter<T> for Ipv4Formatter
249where
250 T: Into<Ipv4Addr>,
251{
252 fn format(v: T) -> String {
253 v.into().to_string()
254 }
255}
256
257pub struct Ipv6Formatter;
258impl<T> Formatter<T> for Ipv6Formatter
259where
260 T: Into<Ipv6Addr>,
261{
262 fn format(v: T) -> String {
263 v.into().to_string()
264 }
265}
266
267pub struct LowerMacFormatter;
268impl Formatter<[u8; 6]> for LowerMacFormatter {
269 fn format(v: [u8; 6]) -> String {
270 format!(
271 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
272 v[0], v[1], v[2], v[3], v[4], v[5]
273 )
274 }
275}
276
277pub struct UpperMacFormatter;
278impl Formatter<[u8; 6]> for UpperMacFormatter {
279 fn format(v: [u8; 6]) -> String {
280 format!(
281 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
282 v[0], v[1], v[2], v[3], v[4], v[5]
283 )
284 }
285}
286
287pub struct PointerFormatter;
288
289impl<T> Formatter<*const T> for PointerFormatter {
290 #[expect(clippy::pointer_format, reason = "that's the point")]
291 fn format(v: *const T) -> String {
292 format!("{v:p}")
293 }
294}
295
296impl<T> Formatter<*mut T> for PointerFormatter {
297 #[expect(clippy::pointer_format, reason = "that's the point")]
298 fn format(v: *mut T) -> String {
299 format!("{v:p}")
300 }
301}
302
303trait Format {
304 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()>;
305}
306
307impl Format for &[u8] {
308 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
309 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
310 Some(DisplayHint::LowerHex) => Ok(LowerHexBytesFormatter::format(self)),
311 Some(DisplayHint::UpperHex) => Ok(UpperHexBytesFormatter::format(self)),
312 _ => Err(()),
313 }
314 }
315}
316
317impl Format for u32 {
318 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
319 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
320 Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
321 Some(DisplayHint::LowerHex) => Ok(LowerHexFormatter::format(self)),
322 Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)),
323 Some(DisplayHint::Ip) => Ok(Ipv4Formatter::format(*self)),
324 Some(DisplayHint::LowerMac) => Err(()),
325 Some(DisplayHint::UpperMac) => Err(()),
326 Some(DisplayHint::Pointer) => Err(()),
327 None => Ok(DefaultFormatter::format(self)),
328 }
329 }
330}
331
332impl Format for Ipv4Addr {
333 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
334 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
335 Some(DisplayHint::Default) => Ok(Ipv4Formatter::format(*self)),
336 Some(DisplayHint::LowerHex) => Err(()),
337 Some(DisplayHint::UpperHex) => Err(()),
338 Some(DisplayHint::Ip) => Ok(Ipv4Formatter::format(*self)),
339 Some(DisplayHint::LowerMac) => Err(()),
340 Some(DisplayHint::UpperMac) => Err(()),
341 Some(DisplayHint::Pointer) => Err(()),
342 None => Ok(Ipv4Formatter::format(*self)),
343 }
344 }
345}
346
347impl Format for Ipv6Addr {
348 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
349 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
350 Some(DisplayHint::Default) => Ok(Ipv6Formatter::format(*self)),
351 Some(DisplayHint::LowerHex) => Err(()),
352 Some(DisplayHint::UpperHex) => Err(()),
353 Some(DisplayHint::Ip) => Ok(Ipv6Formatter::format(*self)),
354 Some(DisplayHint::LowerMac) => Err(()),
355 Some(DisplayHint::UpperMac) => Err(()),
356 Some(DisplayHint::Pointer) => Err(()),
357 None => Ok(Ipv6Formatter::format(*self)),
358 }
359 }
360}
361
362impl Format for [u8; 4] {
363 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
364 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
365 Some(DisplayHint::Default) => Ok(Ipv4Formatter::format(*self)),
366 Some(DisplayHint::LowerHex) => Err(()),
367 Some(DisplayHint::UpperHex) => Err(()),
368 Some(DisplayHint::Ip) => Ok(Ipv4Formatter::format(*self)),
369 Some(DisplayHint::LowerMac) => Err(()),
370 Some(DisplayHint::UpperMac) => Err(()),
371 Some(DisplayHint::Pointer) => Err(()),
372 None => Ok(Ipv4Formatter::format(*self)),
373 }
374 }
375}
376
377impl Format for [u8; 6] {
378 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
379 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
380 Some(DisplayHint::Default) => Err(()),
381 Some(DisplayHint::LowerHex) => Err(()),
382 Some(DisplayHint::UpperHex) => Err(()),
383 Some(DisplayHint::Ip) => Err(()),
384 Some(DisplayHint::LowerMac) => Ok(LowerMacFormatter::format(*self)),
385 Some(DisplayHint::UpperMac) => Ok(UpperMacFormatter::format(*self)),
386 Some(DisplayHint::Pointer) => Err(()),
387 None => Err(()),
388 }
389 }
390}
391
392impl Format for [u8; 16] {
393 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
394 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
395 Some(DisplayHint::Default) => Err(()),
396 Some(DisplayHint::LowerHex) => Err(()),
397 Some(DisplayHint::UpperHex) => Err(()),
398 Some(DisplayHint::Ip) => Ok(Ipv6Formatter::format(*self)),
399 Some(DisplayHint::LowerMac) => Err(()),
400 Some(DisplayHint::UpperMac) => Err(()),
401 Some(DisplayHint::Pointer) => Err(()),
402 None => Err(()),
403 }
404 }
405}
406
407impl Format for [u16; 8] {
408 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
409 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
410 Some(DisplayHint::Default) => Err(()),
411 Some(DisplayHint::LowerHex) => Err(()),
412 Some(DisplayHint::UpperHex) => Err(()),
413 Some(DisplayHint::Ip) => Ok(Ipv6Formatter::format(*self)),
414 Some(DisplayHint::LowerMac) => Err(()),
415 Some(DisplayHint::UpperMac) => Err(()),
416 Some(DisplayHint::Pointer) => Err(()),
417 None => Err(()),
418 }
419 }
420}
421
422macro_rules! impl_format {
423 ($type:ident) => {
424 impl Format for $type {
425 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
426 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
427 Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
428 Some(DisplayHint::LowerHex) => Ok(LowerHexFormatter::format(self)),
429 Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)),
430 Some(DisplayHint::Ip) => Err(()),
431 Some(DisplayHint::LowerMac) => Err(()),
432 Some(DisplayHint::UpperMac) => Err(()),
433 Some(DisplayHint::Pointer) => Err(()),
434 None => Ok(DefaultFormatter::format(self)),
435 }
436 }
437 }
438 };
439}
440
441impl_format!(i8);
442impl_format!(i16);
443impl_format!(i32);
444impl_format!(i64);
445impl_format!(isize);
446
447impl_format!(u8);
448impl_format!(u16);
449impl_format!(u64);
450impl_format!(usize);
451
452macro_rules! impl_format_float {
453 ($type:ident) => {
454 impl Format for $type {
455 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
456 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
457 Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
458 Some(DisplayHint::LowerHex) => Err(()),
459 Some(DisplayHint::UpperHex) => Err(()),
460 Some(DisplayHint::Ip) => Err(()),
461 Some(DisplayHint::LowerMac) => Err(()),
462 Some(DisplayHint::UpperMac) => Err(()),
463 Some(DisplayHint::Pointer) => Err(()),
464 None => Ok(DefaultFormatter::format(self)),
465 }
466 }
467 }
468 };
469}
470
471impl_format_float!(f32);
472impl_format_float!(f64);
473
474impl<T> Format for *const T {
475 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
476 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
477 Some(DisplayHint::Pointer) => Ok(PointerFormatter::format(*self)),
478 _ => Err(()),
479 }
480 }
481}
482
483impl<T> Format for *mut T {
484 fn format(&self, last_hint: Option<DisplayHintWrapper>) -> Result<String, ()> {
485 match last_hint.map(|DisplayHintWrapper(dh)| dh) {
486 Some(DisplayHint::Pointer) => Ok(PointerFormatter::format(*self)),
487 _ => Err(()),
488 }
489 }
490}
491
492#[derive(Error, Debug)]
493pub enum Error {
494 #[error("{} not found", MAP_NAME)]
495 MapNotFound,
496
497 #[error(transparent)]
498 MapError(#[from] MapError),
499
500 #[error("program not found")]
501 ProgramNotFound,
502
503 #[error(transparent)]
504 ProgramError(#[from] ProgramError),
505}
506
507fn log_buf<T: ?Sized + Log>(mut buf: &[u8], logger: &T) -> Result<(), ()> {
508 let size = LogValueLength::from_ne_bytes(
509 buf.get(..size_of::<LogValueLength>())
510 .ok_or(())?
511 .try_into()
512 .map_err(|std::array::TryFromSliceError { .. }| ())?,
513 )
514 .into();
515 buf = buf.get(size_of::<LogValueLength>()..size).ok_or(())?;
516
517 let mut target = None;
518 let mut level = None;
519 let mut module = None;
520 let mut file = None;
521 let mut line = None;
522 let mut num_args = None;
523
524 while target.is_none()
525 || level.is_none()
526 || module.is_none()
527 || file.is_none()
528 || line.is_none()
529 || num_args.is_none()
530 {
531 let (RecordFieldWrapper(tag), value, rest) = try_read(buf)?;
532
533 match tag {
534 RecordFieldKind::Target => {
535 let target =
536 target.replace(str::from_utf8(value).map_err(|str::Utf8Error { .. }| ())?);
537 if target.is_some() {
538 return Err(());
539 }
540 }
541 RecordFieldKind::Level => {
542 let level = level.replace({
543 let level = unsafe { ptr::read_unaligned(value.as_ptr().cast()) };
544 match level {
545 Level::Error => log::Level::Error,
546 Level::Warn => log::Level::Warn,
547 Level::Info => log::Level::Info,
548 Level::Debug => log::Level::Debug,
549 Level::Trace => log::Level::Trace,
550 }
551 });
552 if level.is_some() {
553 return Err(());
554 }
555 }
556 RecordFieldKind::Module => {
557 let module =
558 module.replace(str::from_utf8(value).map_err(|str::Utf8Error { .. }| ())?);
559 if module.is_some() {
560 return Err(());
561 }
562 }
563 RecordFieldKind::File => {
564 let file = file.replace(str::from_utf8(value).map_err(|str::Utf8Error { .. }| ())?);
565 if file.is_some() {
566 return Err(());
567 }
568 }
569 RecordFieldKind::Line => {
570 let line = line.replace(u32::from_ne_bytes(
571 value
572 .try_into()
573 .map_err(|std::array::TryFromSliceError { .. }| ())?,
574 ));
575 if line.is_some() {
576 return Err(());
577 }
578 }
579 RecordFieldKind::NumArgs => {
580 let num_args = num_args.replace(u32::from_ne_bytes(
581 value
582 .try_into()
583 .map_err(|std::array::TryFromSliceError { .. }| ())?,
584 ));
585 if num_args.is_some() {
586 return Err(());
587 }
588 }
589 }
590
591 buf = rest;
592 }
593
594 let mut full_log_msg = String::new();
595 let mut last_hint: Option<DisplayHintWrapper> = None;
596 let num_args = num_args.ok_or(()).and_then(|num_args| {
597 usize::try_from(num_args).map_err(|std::num::TryFromIntError { .. }| ())
598 })?;
599 for () in std::iter::repeat_n((), num_args) {
600 let (ArgumentWrapper(tag), value, rest) = try_read(buf)?;
601
602 match tag {
603 ArgumentKind::DisplayHint => {
604 last_hint = Some(unsafe { ptr::read_unaligned(value.as_ptr().cast()) });
605 }
606 ArgumentKind::I8 => {
607 full_log_msg.push_str(
608 &i8::from_ne_bytes(
609 value
610 .try_into()
611 .map_err(|std::array::TryFromSliceError { .. }| ())?,
612 )
613 .format(last_hint.take())?,
614 );
615 }
616 ArgumentKind::I16 => {
617 full_log_msg.push_str(
618 &i16::from_ne_bytes(
619 value
620 .try_into()
621 .map_err(|std::array::TryFromSliceError { .. }| ())?,
622 )
623 .format(last_hint.take())?,
624 );
625 }
626 ArgumentKind::I32 => {
627 full_log_msg.push_str(
628 &i32::from_ne_bytes(
629 value
630 .try_into()
631 .map_err(|std::array::TryFromSliceError { .. }| ())?,
632 )
633 .format(last_hint.take())?,
634 );
635 }
636 ArgumentKind::I64 => {
637 full_log_msg.push_str(
638 &i64::from_ne_bytes(
639 value
640 .try_into()
641 .map_err(|std::array::TryFromSliceError { .. }| ())?,
642 )
643 .format(last_hint.take())?,
644 );
645 }
646 ArgumentKind::Isize => {
647 full_log_msg.push_str(
648 &isize::from_ne_bytes(
649 value
650 .try_into()
651 .map_err(|std::array::TryFromSliceError { .. }| ())?,
652 )
653 .format(last_hint.take())?,
654 );
655 }
656 ArgumentKind::U8 => {
657 full_log_msg.push_str(
658 &u8::from_ne_bytes(
659 value
660 .try_into()
661 .map_err(|std::array::TryFromSliceError { .. }| ())?,
662 )
663 .format(last_hint.take())?,
664 );
665 }
666 ArgumentKind::U16 => {
667 full_log_msg.push_str(
668 &u16::from_ne_bytes(
669 value
670 .try_into()
671 .map_err(|std::array::TryFromSliceError { .. }| ())?,
672 )
673 .format(last_hint.take())?,
674 );
675 }
676 ArgumentKind::U32 => {
677 full_log_msg.push_str(
678 &u32::from_ne_bytes(
679 value
680 .try_into()
681 .map_err(|std::array::TryFromSliceError { .. }| ())?,
682 )
683 .format(last_hint.take())?,
684 );
685 }
686 ArgumentKind::U64 => {
687 full_log_msg.push_str(
688 &u64::from_ne_bytes(
689 value
690 .try_into()
691 .map_err(|std::array::TryFromSliceError { .. }| ())?,
692 )
693 .format(last_hint.take())?,
694 );
695 }
696 ArgumentKind::Usize => {
697 full_log_msg.push_str(
698 &usize::from_ne_bytes(
699 value
700 .try_into()
701 .map_err(|std::array::TryFromSliceError { .. }| ())?,
702 )
703 .format(last_hint.take())?,
704 );
705 }
706 ArgumentKind::F32 => {
707 full_log_msg.push_str(
708 &f32::from_ne_bytes(
709 value
710 .try_into()
711 .map_err(|std::array::TryFromSliceError { .. }| ())?,
712 )
713 .format(last_hint.take())?,
714 );
715 }
716 ArgumentKind::F64 => {
717 full_log_msg.push_str(
718 &f64::from_ne_bytes(
719 value
720 .try_into()
721 .map_err(|std::array::TryFromSliceError { .. }| ())?,
722 )
723 .format(last_hint.take())?,
724 );
725 }
726 ArgumentKind::Ipv4Addr => {
727 let value: [u8; 4] = value
728 .try_into()
729 .map_err(|std::array::TryFromSliceError { .. }| ())?;
730 let value = Ipv4Addr::from(value);
731 full_log_msg.push_str(&value.format(last_hint.take())?)
732 }
733 ArgumentKind::Ipv6Addr => {
734 let value: [u8; 16] = value
735 .try_into()
736 .map_err(|std::array::TryFromSliceError { .. }| ())?;
737 let value = Ipv6Addr::from(value);
738 full_log_msg.push_str(&value.format(last_hint.take())?)
739 }
740 ArgumentKind::ArrU8Len4 => {
741 let value: [u8; 4] = value
742 .try_into()
743 .map_err(|std::array::TryFromSliceError { .. }| ())?;
744 full_log_msg.push_str(&value.format(last_hint.take())?);
745 }
746 ArgumentKind::ArrU8Len6 => {
747 let value: [u8; 6] = value
748 .try_into()
749 .map_err(|std::array::TryFromSliceError { .. }| ())?;
750 full_log_msg.push_str(&value.format(last_hint.take())?);
751 }
752 ArgumentKind::ArrU8Len16 => {
753 let value: [u8; 16] = value
754 .try_into()
755 .map_err(|std::array::TryFromSliceError { .. }| ())?;
756 full_log_msg.push_str(&value.format(last_hint.take())?);
757 }
758 ArgumentKind::ArrU16Len8 => {
759 let data: [u8; 16] = value
760 .try_into()
761 .map_err(|std::array::TryFromSliceError { .. }| ())?;
762 let mut value: [u16; 8] = Default::default();
763 for (i, s) in data.chunks_exact(2).enumerate() {
764 value[i] = (u16::from(s[1]) << 8) | u16::from(s[0]);
765 }
766 full_log_msg.push_str(&value.format(last_hint.take())?);
767 }
768 ArgumentKind::Bytes => {
769 full_log_msg.push_str(&value.format(last_hint.take())?);
770 }
771 ArgumentKind::Str => match str::from_utf8(value) {
772 Ok(v) => {
773 full_log_msg.push_str(v);
774 }
775 Err(e) => error!("received invalid utf8 string: {e}"),
776 },
777 ArgumentKind::Pointer => {
778 let value = value
779 .try_into()
780 .map_err(|std::array::TryFromSliceError { .. }| ())?;
781 let ptr = usize::from_ne_bytes(value) as *const ();
782 full_log_msg.push_str(&ptr.format(last_hint.take())?);
783 }
784 }
785
786 buf = rest;
787 }
788
789 logger.log(
790 &Record::builder()
791 .args(format_args!("{full_log_msg}"))
792 .target(target.ok_or(())?)
793 .level(level.ok_or(())?)
794 .module_path(module)
795 .file(file)
796 .line(line)
797 .build(),
798 );
799 logger.flush();
800 Ok(())
801}
802
803fn try_read<T: Pod>(mut buf: &[u8]) -> Result<(T, &[u8], &[u8]), ()> {
804 if buf.len() < size_of::<T>() + size_of::<LogValueLength>() {
805 return Err(());
806 }
807
808 let tag = unsafe { ptr::read_unaligned(buf.as_ptr().cast::<T>()) };
809 buf = &buf[size_of::<T>()..];
810
811 let len = LogValueLength::from_ne_bytes(buf[..size_of::<LogValueLength>()].try_into().unwrap());
812 buf = &buf[size_of::<LogValueLength>()..];
813
814 let len: usize = len.into();
815 if buf.len() < len {
816 return Err(());
817 }
818
819 let (value, rest) = buf.split_at(len);
820 Ok((tag, value, rest))
821}
822
823#[cfg(test)]
824mod test {
825 use std::{net::IpAddr, num::NonZeroUsize};
826
827 use aya_log_common::{Argument, Field, Header};
828 use log::{Level, logger};
829
830 trait WriteToBuf {
831 fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize>;
832 }
833
834 impl<T: Argument> WriteToBuf for T {
835 fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
836 let (kind, value) = self.as_argument();
837 let field = Field::new(kind, value)?;
838 let mut size = 0;
839 let mut op = |slice: &[u8]| {
840 let buf = buf.get_mut(size..)?;
841 let buf = buf.get_mut(..slice.len())?;
842 buf.copy_from_slice(slice);
843 size += slice.len();
844 Some(())
845 };
846 field.with_bytes(&mut op)?;
847 NonZeroUsize::new(size)
848 }
849 }
850
851 use super::*;
852
853 fn write_record_header(
854 buf: &mut [u8],
855 target: &str,
856 level: aya_log_common::Level,
857 module: &str,
858 file: &str,
859 line: u32,
860 num_args: u32,
861 ) -> Option<NonZeroUsize> {
862 let header = Header::new(target, level, module, file, line, num_args)?;
863 let mut size = 0;
864 let mut op = |slice: &[u8]| {
865 let buf = buf.get_mut(size..)?;
866 let buf = buf.get_mut(..slice.len())?;
867 buf.copy_from_slice(slice);
868 size += slice.len();
869 Some(())
870 };
871 header.with_bytes(&mut op)?;
872 NonZeroUsize::new(size)
873 }
874
875 fn new_log(args: u32) -> Option<(usize, Vec<u8>)> {
876 let mut buf = vec![0; 8192];
877 let len = write_record_header(
878 &mut buf,
879 "test",
880 aya_log_common::Level::Info,
881 "test",
882 "test.rs",
883 123,
884 args,
885 )?;
886 Some((len.get(), buf))
887 }
888
889 #[test]
890 fn test_str() {
891 testing_logger::setup();
892 let (mut len, mut input) = new_log(1).unwrap();
893
894 len += "test".write(&mut input[len..]).unwrap().get();
895
896 let len = u16::try_from(len).unwrap();
897 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
898
899 let logger = logger();
900 let () = log_buf(&input, logger).unwrap();
901 testing_logger::validate(|captured_logs| {
902 assert_eq!(captured_logs.len(), 1);
903 assert_eq!(captured_logs[0].body, "test");
904 assert_eq!(captured_logs[0].level, Level::Info);
905 });
906 }
907
908 #[test]
909 fn test_str_with_args() {
910 testing_logger::setup();
911 let (mut len, mut input) = new_log(2).unwrap();
912
913 len += "hello ".write(&mut input[len..]).unwrap().get();
914 len += "test".write(&mut input[len..]).unwrap().get();
915
916 let len = u16::try_from(len).unwrap();
917 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
918
919 let logger = logger();
920 let () = log_buf(&input, logger).unwrap();
921 testing_logger::validate(|captured_logs| {
922 assert_eq!(captured_logs.len(), 1);
923 assert_eq!(captured_logs[0].body, "hello test");
924 assert_eq!(captured_logs[0].level, Level::Info);
925 });
926 }
927
928 #[test]
929 fn test_bytes() {
930 testing_logger::setup();
931 let (mut len, mut input) = new_log(2).unwrap();
932
933 len += DisplayHint::LowerHex
934 .write(&mut input[len..])
935 .unwrap()
936 .get();
937 len += [0xde, 0xad].write(&mut input[len..]).unwrap().get();
938
939 let len = u16::try_from(len).unwrap();
940 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
941
942 let logger = logger();
943 let () = log_buf(&input, logger).unwrap();
944 testing_logger::validate(|captured_logs| {
945 assert_eq!(captured_logs.len(), 1);
946 assert_eq!(captured_logs[0].body, "dead");
947 assert_eq!(captured_logs[0].level, Level::Info);
948 });
949 }
950
951 #[test]
952 fn test_bytes_with_args() {
953 testing_logger::setup();
954 let (mut len, mut input) = new_log(5).unwrap();
955
956 len += DisplayHint::LowerHex
957 .write(&mut input[len..])
958 .unwrap()
959 .get();
960 len += [0xde, 0xad].write(&mut input[len..]).unwrap().get();
961
962 len += " ".write(&mut input[len..]).unwrap().get();
963
964 len += DisplayHint::UpperHex
965 .write(&mut input[len..])
966 .unwrap()
967 .get();
968 len += [0xbe, 0xef].write(&mut input[len..]).unwrap().get();
969
970 let len = u16::try_from(len).unwrap();
971 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
972
973 let logger = logger();
974 let () = log_buf(&input, logger).unwrap();
975 testing_logger::validate(|captured_logs| {
976 assert_eq!(captured_logs.len(), 1);
977 assert_eq!(captured_logs[0].body, "dead BEEF");
978 assert_eq!(captured_logs[0].level, Level::Info);
979 });
980 }
981
982 #[test]
983 fn test_bytes_unambiguous() {
984 testing_logger::setup();
985 let (mut len, mut input) = new_log(5).unwrap();
986
987 len += DisplayHint::LowerHex
988 .write(&mut input[len..])
989 .unwrap()
990 .get();
991 len += [0x01, 0x02].write(&mut input[len..]).unwrap().get();
992
993 len += " ".write(&mut input[len..]).unwrap().get();
994
995 len += DisplayHint::LowerHex
996 .write(&mut input[len..])
997 .unwrap()
998 .get();
999 len += [0x12].write(&mut input[len..]).unwrap().get();
1000
1001 let len = u16::try_from(len).unwrap();
1002 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1003
1004 let logger = logger();
1005 let () = log_buf(&input, logger).unwrap();
1006 testing_logger::validate(|captured_logs| {
1007 assert_eq!(captured_logs.len(), 1);
1008 assert_eq!(captured_logs[0].body, "0102 12");
1009 assert_eq!(captured_logs[0].level, Level::Info);
1010 });
1011 }
1012
1013 #[test]
1014 fn test_display_hint_default() {
1015 testing_logger::setup();
1016 let (mut len, mut input) = new_log(3).unwrap();
1017
1018 len += "default hint: ".write(&mut input[len..]).unwrap().get();
1019 len += DisplayHint::Default.write(&mut input[len..]).unwrap().get();
1020 len += 14.write(&mut input[len..]).unwrap().get();
1021
1022 let len = u16::try_from(len).unwrap();
1023 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1024
1025 let logger = logger();
1026 let () = log_buf(&input, logger).unwrap();
1027 testing_logger::validate(|captured_logs| {
1028 assert_eq!(captured_logs.len(), 1);
1029 assert_eq!(captured_logs[0].body, "default hint: 14");
1030 assert_eq!(captured_logs[0].level, Level::Info);
1031 });
1032 }
1033
1034 #[test]
1035 fn test_display_hint_lower_hex() {
1036 testing_logger::setup();
1037 let (mut len, mut input) = new_log(3).unwrap();
1038
1039 len += "lower hex: ".write(&mut input[len..]).unwrap().get();
1040 len += DisplayHint::LowerHex
1041 .write(&mut input[len..])
1042 .unwrap()
1043 .get();
1044 len += 200.write(&mut input[len..]).unwrap().get();
1045
1046 let len = u16::try_from(len).unwrap();
1047 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1048
1049 let logger = logger();
1050 let () = log_buf(&input, logger).unwrap();
1051 testing_logger::validate(|captured_logs| {
1052 assert_eq!(captured_logs.len(), 1);
1053 assert_eq!(captured_logs[0].body, "lower hex: c8");
1054 assert_eq!(captured_logs[0].level, Level::Info);
1055 });
1056 }
1057
1058 #[test]
1059 fn test_display_hint_upper_hex() {
1060 testing_logger::setup();
1061 let (mut len, mut input) = new_log(3).unwrap();
1062
1063 len += "upper hex: ".write(&mut input[len..]).unwrap().get();
1064 len += DisplayHint::UpperHex
1065 .write(&mut input[len..])
1066 .unwrap()
1067 .get();
1068 len += 200.write(&mut input[len..]).unwrap().get();
1069
1070 let len = u16::try_from(len).unwrap();
1071 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1072
1073 let logger = logger();
1074 let () = log_buf(&input, logger).unwrap();
1075 testing_logger::validate(|captured_logs| {
1076 assert_eq!(captured_logs.len(), 1);
1077 assert_eq!(captured_logs[0].body, "upper hex: C8");
1078 assert_eq!(captured_logs[0].level, Level::Info);
1079 });
1080 }
1081
1082 #[test]
1083 fn test_display_hint_ipv4() {
1084 testing_logger::setup();
1085 let (mut len, mut input) = new_log(3).unwrap();
1086
1087 len += "ipv4: ".write(&mut input[len..]).unwrap().get();
1088 len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1089 len += Ipv4Addr::new(10, 0, 0, 1)
1090 .write(&mut input[len..])
1091 .unwrap()
1092 .get();
1093
1094 let len = u16::try_from(len).unwrap();
1095 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1096
1097 let logger = logger();
1098 let () = log_buf(&input, logger).unwrap();
1099 testing_logger::validate(|captured_logs| {
1100 assert_eq!(captured_logs.len(), 1);
1101 assert_eq!(captured_logs[0].body, "ipv4: 10.0.0.1");
1102 assert_eq!(captured_logs[0].level, Level::Info);
1103 });
1104 }
1105
1106 #[test]
1107 fn test_display_hint_ip_ipv4() {
1108 testing_logger::setup();
1109 let (mut len, mut input) = new_log(3).unwrap();
1110
1111 len += "ipv4: ".write(&mut input[len..]).unwrap().get();
1112 len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1113 len += IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))
1114 .write(&mut input[len..])
1115 .unwrap()
1116 .get();
1117
1118 let len = u16::try_from(len).unwrap();
1119 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1120
1121 let logger = logger();
1122 let () = log_buf(&input, logger).unwrap();
1123 testing_logger::validate(|captured_logs| {
1124 assert_eq!(captured_logs.len(), 1);
1125 assert_eq!(captured_logs[0].body, "ipv4: 10.0.0.1");
1126 assert_eq!(captured_logs[0].level, Level::Info);
1127 });
1128 }
1129
1130 #[test]
1131 fn test_display_hint_ipv4_u32() {
1132 testing_logger::setup();
1133 let (mut len, mut input) = new_log(3).unwrap();
1134
1135 len += "ipv4: ".write(&mut input[len..]).unwrap().get();
1136 len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1137 len += 167772161u32.write(&mut input[len..]).unwrap().get();
1139
1140 let len = u16::try_from(len).unwrap();
1141 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1142
1143 let logger = logger();
1144 let () = log_buf(&input, logger).unwrap();
1145 testing_logger::validate(|captured_logs| {
1146 assert_eq!(captured_logs.len(), 1);
1147 assert_eq!(captured_logs[0].body, "ipv4: 10.0.0.1");
1148 assert_eq!(captured_logs[0].level, Level::Info);
1149 });
1150 }
1151
1152 #[test]
1153 fn test_display_hint_ipv6() {
1154 testing_logger::setup();
1155 let (mut len, mut input) = new_log(3).unwrap();
1156
1157 len += "ipv6: ".write(&mut input[len..]).unwrap().get();
1158 len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1159 len += Ipv6Addr::new(
1160 0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001,
1161 )
1162 .write(&mut input[len..])
1163 .unwrap()
1164 .get();
1165
1166 let len = u16::try_from(len).unwrap();
1167 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1168
1169 let logger = logger();
1170 let () = log_buf(&input, logger).unwrap();
1171 testing_logger::validate(|captured_logs| {
1172 assert_eq!(captured_logs.len(), 1);
1173 assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
1174 assert_eq!(captured_logs[0].level, Level::Info);
1175 });
1176 }
1177
1178 #[test]
1179 fn test_display_hint_ip_ipv6() {
1180 testing_logger::setup();
1181 let (mut len, mut input) = new_log(3).unwrap();
1182
1183 len += "ipv6: ".write(&mut input[len..]).unwrap().get();
1184 len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1185 len += IpAddr::V6(Ipv6Addr::new(
1186 0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001,
1187 ))
1188 .write(&mut input[len..])
1189 .unwrap()
1190 .get();
1191
1192 let len = u16::try_from(len).unwrap();
1193 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1194
1195 let logger = logger();
1196 let () = log_buf(&input, logger).unwrap();
1197 testing_logger::validate(|captured_logs| {
1198 assert_eq!(captured_logs.len(), 1);
1199 assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
1200 assert_eq!(captured_logs[0].level, Level::Info);
1201 });
1202 }
1203
1204 #[test]
1205 fn test_display_hint_ipv6_arr_u8_len_16() {
1206 testing_logger::setup();
1207 let (mut len, mut input) = new_log(3).unwrap();
1208
1209 len += "ipv6: ".write(&mut input[len..]).unwrap().get();
1210 len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1211 let ipv6_arr: [u8; 16] = [
1213 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1214 0x00, 0x01,
1215 ];
1216 len += ipv6_arr.write(&mut input[len..]).unwrap().get();
1217
1218 let len = u16::try_from(len).unwrap();
1219 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1220
1221 let logger = logger();
1222 let () = log_buf(&input, logger).unwrap();
1223 testing_logger::validate(|captured_logs| {
1224 assert_eq!(captured_logs.len(), 1);
1225 assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
1226 assert_eq!(captured_logs[0].level, Level::Info);
1227 });
1228 }
1229
1230 #[test]
1231 fn test_display_hint_ipv6_arr_u16_len_8() {
1232 testing_logger::setup();
1233 let (mut len, mut input) = new_log(3).unwrap();
1234
1235 len += "ipv6: ".write(&mut input[len..]).unwrap().get();
1236 len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
1237
1238 let ipv6 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0x1, 0x1);
1239 let ipv6_arr = ipv6.octets();
1240 len += ipv6_arr.write(&mut input[len..]).unwrap().get();
1241
1242 let len = u16::try_from(len).unwrap();
1243 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1244
1245 let logger = logger();
1246 let () = log_buf(&input, logger).unwrap();
1247 testing_logger::validate(|captured_logs| {
1248 assert_eq!(captured_logs.len(), 1);
1249 assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
1250 assert_eq!(captured_logs[0].level, Level::Info);
1251 });
1252 }
1253
1254 #[test]
1255 fn test_display_hint_lower_mac() {
1256 testing_logger::setup();
1257 let (mut len, mut input) = new_log(3).unwrap();
1258
1259 len += "mac: ".write(&mut input[len..]).unwrap().get();
1260 len += DisplayHint::LowerMac
1261 .write(&mut input[len..])
1262 .unwrap()
1263 .get();
1264 let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf];
1266 len += mac_arr.write(&mut input[len..]).unwrap().get();
1267
1268 let len = u16::try_from(len).unwrap();
1269 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1270
1271 let logger = logger();
1272 let () = log_buf(&input, logger).unwrap();
1273 testing_logger::validate(|captured_logs| {
1274 assert_eq!(captured_logs.len(), 1);
1275 assert_eq!(captured_logs[0].body, "mac: 00:00:5e:00:53:af");
1276 assert_eq!(captured_logs[0].level, Level::Info);
1277 });
1278 }
1279
1280 #[test]
1281 fn test_display_hint_upper_mac() {
1282 testing_logger::setup();
1283 let (mut len, mut input) = new_log(3).unwrap();
1284
1285 len += "mac: ".write(&mut input[len..]).unwrap().get();
1286 len += DisplayHint::UpperMac
1287 .write(&mut input[len..])
1288 .unwrap()
1289 .get();
1290 let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf];
1292 len += mac_arr.write(&mut input[len..]).unwrap().get();
1293
1294 let len = u16::try_from(len).unwrap();
1295 input.splice(0..0, (len + 2).to_ne_bytes().iter().copied());
1296
1297 let logger = logger();
1298 let () = log_buf(&input, logger).unwrap();
1299 testing_logger::validate(|captured_logs| {
1300 assert_eq!(captured_logs.len(), 1);
1301 assert_eq!(captured_logs[0].body, "mac: 00:00:5E:00:53:AF");
1302 assert_eq!(captured_logs[0].level, Level::Info);
1303 });
1304 }
1305}