1use 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)] #[derive(Copy, Clone)]
80#[repr(transparent)]
81struct RecordFieldWrapper(RecordField);
82#[allow(dead_code)] #[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
94pub struct EbpfLogger;
98
99#[deprecated(since = "0.2.1", note = "Use `aya_log::EbpfLogger` instead")]
101pub type BpfLogger = EbpfLogger;
102
103impl EbpfLogger {
104 pub fn init(bpf: &mut Ebpf) -> Result<EbpfLogger, Error> {
107 EbpfLogger::init_with_logger(bpf, log::logger())
108 }
109
110 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 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 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 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 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 #[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 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 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}