lib.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  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 [BpfLogger] 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::Bpf::load(&[]).unwrap();
  16. //! use aya_log::BpfLogger;
  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. //! BpfLogger::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. //!
  52. use std::{
  53. fmt::{LowerHex, UpperHex},
  54. io, mem,
  55. net::{Ipv4Addr, Ipv6Addr},
  56. ptr, str,
  57. sync::Arc,
  58. };
  59. use aya_log_common::{Argument, DisplayHint, RecordField, LOG_BUF_CAPACITY, LOG_FIELDS};
  60. use bytes::BytesMut;
  61. use log::{error, Level, Log, Record};
  62. use thiserror::Error;
  63. use aya::{
  64. maps::{
  65. perf::{AsyncPerfEventArray, PerfBufferError},
  66. MapError,
  67. },
  68. util::online_cpus,
  69. Bpf, Pod,
  70. };
  71. /// Log messages generated by `aya_log_ebpf` using the [log] crate.
  72. ///
  73. /// For more details see the [module level documentation](crate).
  74. pub struct BpfLogger;
  75. impl BpfLogger {
  76. /// Starts reading log records created with `aya-log-ebpf` and logs them
  77. /// with the default logger. See [log::logger].
  78. pub fn init(bpf: &mut Bpf) -> Result<BpfLogger, Error> {
  79. BpfLogger::init_with_logger(bpf, DefaultLogger {})
  80. }
  81. /// Starts reading log records created with `aya-log-ebpf` and logs them
  82. /// with the given logger.
  83. pub fn init_with_logger<T: Log + 'static>(
  84. bpf: &mut Bpf,
  85. logger: T,
  86. ) -> Result<BpfLogger, Error> {
  87. let logger = Arc::new(logger);
  88. let mut logs: AsyncPerfEventArray<_> = bpf.take_map("AYA_LOGS").unwrap().try_into()?;
  89. for cpu_id in online_cpus().map_err(Error::InvalidOnlineCpu)? {
  90. let mut buf = logs.open(cpu_id, None)?;
  91. let log = logger.clone();
  92. tokio::spawn(async move {
  93. let mut buffers = (0..10)
  94. .map(|_| BytesMut::with_capacity(LOG_BUF_CAPACITY))
  95. .collect::<Vec<_>>();
  96. loop {
  97. let events = buf.read_events(&mut buffers).await.unwrap();
  98. #[allow(clippy::needless_range_loop)]
  99. for i in 0..events.read {
  100. let buf = &mut buffers[i];
  101. log_buf(buf, &*log).unwrap();
  102. }
  103. }
  104. });
  105. }
  106. Ok(BpfLogger {})
  107. }
  108. }
  109. pub trait Formatter<T> {
  110. fn format(v: T) -> String;
  111. }
  112. pub struct DefaultFormatter;
  113. impl<T> Formatter<T> for DefaultFormatter
  114. where
  115. T: ToString,
  116. {
  117. fn format(v: T) -> String {
  118. v.to_string()
  119. }
  120. }
  121. pub struct LowerHexFormatter;
  122. impl<T> Formatter<T> for LowerHexFormatter
  123. where
  124. T: LowerHex,
  125. {
  126. fn format(v: T) -> String {
  127. format!("{:x}", v)
  128. }
  129. }
  130. pub struct UpperHexFormatter;
  131. impl<T> Formatter<T> for UpperHexFormatter
  132. where
  133. T: UpperHex,
  134. {
  135. fn format(v: T) -> String {
  136. format!("{:X}", v)
  137. }
  138. }
  139. pub struct Ipv4Formatter;
  140. impl<T> Formatter<T> for Ipv4Formatter
  141. where
  142. T: Into<Ipv4Addr>,
  143. {
  144. fn format(v: T) -> String {
  145. v.into().to_string()
  146. }
  147. }
  148. pub struct Ipv6Formatter;
  149. impl<T> Formatter<T> for Ipv6Formatter
  150. where
  151. T: Into<Ipv6Addr>,
  152. {
  153. fn format(v: T) -> String {
  154. v.into().to_string()
  155. }
  156. }
  157. pub struct LowerMacFormatter;
  158. impl Formatter<[u8; 6]> for LowerMacFormatter {
  159. fn format(v: [u8; 6]) -> String {
  160. format!(
  161. "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
  162. v[0], v[1], v[2], v[3], v[4], v[5]
  163. )
  164. }
  165. }
  166. pub struct UpperMacFormatter;
  167. impl Formatter<[u8; 6]> for UpperMacFormatter {
  168. fn format(v: [u8; 6]) -> String {
  169. format!(
  170. "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
  171. v[0], v[1], v[2], v[3], v[4], v[5]
  172. )
  173. }
  174. }
  175. trait Format {
  176. fn format(&self, last_hint: Option<DisplayHint>) -> Result<String, ()>;
  177. }
  178. impl Format for u32 {
  179. fn format(&self, last_hint: Option<DisplayHint>) -> Result<String, ()> {
  180. match last_hint {
  181. Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
  182. Some(DisplayHint::LowerHex) => Ok(LowerHexFormatter::format(self)),
  183. Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)),
  184. Some(DisplayHint::Ipv4) => Ok(Ipv4Formatter::format(*self)),
  185. Some(DisplayHint::Ipv6) => Err(()),
  186. Some(DisplayHint::LowerMac) => Err(()),
  187. Some(DisplayHint::UpperMac) => Err(()),
  188. _ => Ok(DefaultFormatter::format(self)),
  189. }
  190. }
  191. }
  192. impl Format for [u8; 6] {
  193. fn format(&self, last_hint: Option<DisplayHint>) -> Result<String, ()> {
  194. match last_hint {
  195. Some(DisplayHint::Default) => Err(()),
  196. Some(DisplayHint::LowerHex) => Err(()),
  197. Some(DisplayHint::UpperHex) => Err(()),
  198. Some(DisplayHint::Ipv4) => Err(()),
  199. Some(DisplayHint::Ipv6) => Err(()),
  200. Some(DisplayHint::LowerMac) => Ok(LowerMacFormatter::format(*self)),
  201. Some(DisplayHint::UpperMac) => Ok(UpperMacFormatter::format(*self)),
  202. _ => Err(()),
  203. }
  204. }
  205. }
  206. impl Format for [u8; 16] {
  207. fn format(&self, last_hint: Option<DisplayHint>) -> Result<String, ()> {
  208. match last_hint {
  209. Some(DisplayHint::Default) => Err(()),
  210. Some(DisplayHint::LowerHex) => Err(()),
  211. Some(DisplayHint::UpperHex) => Err(()),
  212. Some(DisplayHint::Ipv4) => Err(()),
  213. Some(DisplayHint::Ipv6) => Ok(Ipv6Formatter::format(*self)),
  214. Some(DisplayHint::LowerMac) => Err(()),
  215. Some(DisplayHint::UpperMac) => Err(()),
  216. _ => Err(()),
  217. }
  218. }
  219. }
  220. impl Format for [u16; 8] {
  221. fn format(&self, last_hint: Option<DisplayHint>) -> Result<String, ()> {
  222. match last_hint {
  223. Some(DisplayHint::Default) => Err(()),
  224. Some(DisplayHint::LowerHex) => Err(()),
  225. Some(DisplayHint::UpperHex) => Err(()),
  226. Some(DisplayHint::Ipv4) => Err(()),
  227. Some(DisplayHint::Ipv6) => Ok(Ipv6Formatter::format(*self)),
  228. Some(DisplayHint::LowerMac) => Err(()),
  229. Some(DisplayHint::UpperMac) => Err(()),
  230. _ => Err(()),
  231. }
  232. }
  233. }
  234. macro_rules! impl_format {
  235. ($type:ident) => {
  236. impl Format for $type {
  237. fn format(&self, last_hint: Option<DisplayHint>) -> Result<String, ()> {
  238. match last_hint {
  239. Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
  240. Some(DisplayHint::LowerHex) => Ok(LowerHexFormatter::format(self)),
  241. Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)),
  242. Some(DisplayHint::Ipv4) => Err(()),
  243. Some(DisplayHint::Ipv6) => Err(()),
  244. Some(DisplayHint::LowerMac) => Err(()),
  245. Some(DisplayHint::UpperMac) => Err(()),
  246. _ => Ok(DefaultFormatter::format(self)),
  247. }
  248. }
  249. }
  250. };
  251. }
  252. impl_format!(i8);
  253. impl_format!(i16);
  254. impl_format!(i32);
  255. impl_format!(i64);
  256. impl_format!(isize);
  257. impl_format!(u8);
  258. impl_format!(u16);
  259. impl_format!(u64);
  260. impl_format!(usize);
  261. macro_rules! impl_format_float {
  262. ($type:ident) => {
  263. impl Format for $type {
  264. fn format(&self, last_hint: Option<DisplayHint>) -> Result<String, ()> {
  265. match last_hint {
  266. Some(DisplayHint::Default) => Ok(DefaultFormatter::format(self)),
  267. Some(DisplayHint::LowerHex) => Err(()),
  268. Some(DisplayHint::UpperHex) => Err(()),
  269. Some(DisplayHint::Ipv4) => Err(()),
  270. Some(DisplayHint::Ipv6) => Err(()),
  271. Some(DisplayHint::LowerMac) => Err(()),
  272. Some(DisplayHint::UpperMac) => Err(()),
  273. _ => Ok(DefaultFormatter::format(self)),
  274. }
  275. }
  276. }
  277. };
  278. }
  279. impl_format_float!(f32);
  280. impl_format_float!(f64);
  281. #[derive(Copy, Clone, Debug)]
  282. struct DefaultLogger;
  283. impl Log for DefaultLogger {
  284. fn enabled(&self, metadata: &log::Metadata) -> bool {
  285. log::logger().enabled(metadata)
  286. }
  287. fn log(&self, record: &Record) {
  288. log::logger().log(record)
  289. }
  290. fn flush(&self) {
  291. log::logger().flush()
  292. }
  293. }
  294. #[derive(Error, Debug)]
  295. pub enum Error {
  296. #[error("error opening log event array")]
  297. MapError(#[from] MapError),
  298. #[error("error opening log buffer")]
  299. PerfBufferError(#[from] PerfBufferError),
  300. #[error("invalid /sys/devices/system/cpu/online format")]
  301. InvalidOnlineCpu(#[source] io::Error),
  302. }
  303. fn log_buf(mut buf: &[u8], logger: &dyn Log) -> Result<(), ()> {
  304. let mut target = None;
  305. let mut level = Level::Trace;
  306. let mut module = None;
  307. let mut file = None;
  308. let mut line = None;
  309. let mut num_args = None;
  310. for _ in 0..LOG_FIELDS {
  311. let (attr, rest) = unsafe { TagLenValue::<'_, RecordField>::try_read(buf)? };
  312. match attr.tag {
  313. RecordField::Target => {
  314. target = Some(std::str::from_utf8(attr.value).map_err(|_| ())?);
  315. }
  316. RecordField::Level => {
  317. level = unsafe { ptr::read_unaligned(attr.value.as_ptr() as *const _) }
  318. }
  319. RecordField::Module => {
  320. module = Some(std::str::from_utf8(attr.value).map_err(|_| ())?);
  321. }
  322. RecordField::File => {
  323. file = Some(std::str::from_utf8(attr.value).map_err(|_| ())?);
  324. }
  325. RecordField::Line => {
  326. line = Some(u32::from_ne_bytes(attr.value.try_into().map_err(|_| ())?));
  327. }
  328. RecordField::NumArgs => {
  329. num_args = Some(usize::from_ne_bytes(attr.value.try_into().map_err(|_| ())?));
  330. }
  331. }
  332. buf = rest;
  333. }
  334. let mut full_log_msg = String::new();
  335. let mut last_hint: Option<DisplayHint> = None;
  336. for _ in 0..num_args.ok_or(())? {
  337. let (attr, rest) = unsafe { TagLenValue::<'_, Argument>::try_read(buf)? };
  338. match attr.tag {
  339. Argument::DisplayHint => {
  340. last_hint = Some(unsafe { ptr::read_unaligned(attr.value.as_ptr() as *const _) });
  341. }
  342. Argument::I8 => {
  343. full_log_msg.push_str(
  344. &i8::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  345. .format(last_hint.take())?,
  346. );
  347. }
  348. Argument::I16 => {
  349. full_log_msg.push_str(
  350. &i16::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  351. .format(last_hint.take())?,
  352. );
  353. }
  354. Argument::I32 => {
  355. full_log_msg.push_str(
  356. &i32::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  357. .format(last_hint.take())?,
  358. );
  359. }
  360. Argument::I64 => {
  361. full_log_msg.push_str(
  362. &i64::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  363. .format(last_hint.take())?,
  364. );
  365. }
  366. Argument::Isize => {
  367. full_log_msg.push_str(
  368. &isize::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  369. .format(last_hint.take())?,
  370. );
  371. }
  372. Argument::U8 => {
  373. full_log_msg.push_str(
  374. &u8::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  375. .format(last_hint.take())?,
  376. );
  377. }
  378. Argument::U16 => {
  379. full_log_msg.push_str(
  380. &u16::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  381. .format(last_hint.take())?,
  382. );
  383. }
  384. Argument::U32 => {
  385. full_log_msg.push_str(
  386. &u32::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  387. .format(last_hint.take())?,
  388. );
  389. }
  390. Argument::U64 => {
  391. full_log_msg.push_str(
  392. &u64::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  393. .format(last_hint.take())?,
  394. );
  395. }
  396. Argument::Usize => {
  397. full_log_msg.push_str(
  398. &usize::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  399. .format(last_hint.take())?,
  400. );
  401. }
  402. Argument::F32 => {
  403. full_log_msg.push_str(
  404. &f32::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  405. .format(last_hint.take())?,
  406. );
  407. }
  408. Argument::F64 => {
  409. full_log_msg.push_str(
  410. &f64::from_ne_bytes(attr.value.try_into().map_err(|_| ())?)
  411. .format(last_hint.take())?,
  412. );
  413. }
  414. Argument::ArrU8Len6 => {
  415. let value: [u8; 6] = attr.value.try_into().map_err(|_| ())?;
  416. full_log_msg.push_str(&value.format(last_hint.take())?);
  417. }
  418. Argument::ArrU8Len16 => {
  419. let value: [u8; 16] = attr.value.try_into().map_err(|_| ())?;
  420. full_log_msg.push_str(&value.format(last_hint.take())?);
  421. }
  422. Argument::ArrU16Len8 => {
  423. let data: [u8; 16] = attr.value.try_into().map_err(|_| ())?;
  424. let mut value: [u16; 8] = Default::default();
  425. for (i, s) in data.chunks_exact(2).enumerate() {
  426. value[i] = ((s[1] as u16) << 8) | s[0] as u16;
  427. }
  428. full_log_msg.push_str(&value.format(last_hint.take())?);
  429. }
  430. Argument::Str => match str::from_utf8(attr.value) {
  431. Ok(v) => {
  432. full_log_msg.push_str(v);
  433. }
  434. Err(e) => error!("received invalid utf8 string: {}", e),
  435. },
  436. }
  437. buf = rest;
  438. }
  439. logger.log(
  440. &Record::builder()
  441. .args(format_args!("{}", full_log_msg))
  442. .target(target.ok_or(())?)
  443. .level(level)
  444. .module_path(module)
  445. .file(file)
  446. .line(line)
  447. .build(),
  448. );
  449. logger.flush();
  450. Ok(())
  451. }
  452. struct TagLenValue<'a, T: Pod> {
  453. tag: T,
  454. value: &'a [u8],
  455. }
  456. impl<'a, T: Pod> TagLenValue<'a, T> {
  457. unsafe fn try_read(mut buf: &'a [u8]) -> Result<(TagLenValue<'a, T>, &'a [u8]), ()> {
  458. if buf.len() < mem::size_of::<T>() + mem::size_of::<usize>() {
  459. return Err(());
  460. }
  461. let tag = ptr::read_unaligned(buf.as_ptr() as *const T);
  462. buf = &buf[mem::size_of::<T>()..];
  463. let len = usize::from_ne_bytes(buf[..mem::size_of::<usize>()].try_into().unwrap());
  464. buf = &buf[mem::size_of::<usize>()..];
  465. if buf.len() < len {
  466. return Err(());
  467. }
  468. Ok((
  469. TagLenValue {
  470. tag,
  471. value: &buf[..len],
  472. },
  473. &buf[len..],
  474. ))
  475. }
  476. }
  477. #[cfg(test)]
  478. mod test {
  479. use super::*;
  480. use aya_log_common::{write_record_header, WriteToBuf};
  481. use log::logger;
  482. use testing_logger;
  483. fn new_log(args: usize) -> Result<(usize, Vec<u8>), ()> {
  484. let mut buf = vec![0; 8192];
  485. let len = write_record_header(
  486. &mut buf,
  487. "test",
  488. aya_log_common::Level::Info,
  489. "test",
  490. "test.rs",
  491. 123,
  492. args,
  493. )?;
  494. Ok((len, buf))
  495. }
  496. #[test]
  497. fn test_str() {
  498. testing_logger::setup();
  499. let (len, mut input) = new_log(1).unwrap();
  500. "test"
  501. .write(&mut input[len..])
  502. .expect("could not write to the buffer");
  503. let logger = logger();
  504. let _ = log_buf(&input, logger);
  505. testing_logger::validate(|captured_logs| {
  506. assert_eq!(captured_logs.len(), 1);
  507. assert_eq!(captured_logs[0].body, "test");
  508. assert_eq!(captured_logs[0].level, Level::Info);
  509. });
  510. }
  511. #[test]
  512. fn test_str_with_args() {
  513. testing_logger::setup();
  514. let (mut len, mut input) = new_log(2).unwrap();
  515. len += "hello "
  516. .write(&mut input[len..])
  517. .expect("could not write to the buffer");
  518. "test".write(&mut input[len..]).unwrap();
  519. let logger = logger();
  520. let _ = log_buf(&input, logger);
  521. testing_logger::validate(|captured_logs| {
  522. assert_eq!(captured_logs.len(), 1);
  523. assert_eq!(captured_logs[0].body, "hello test");
  524. assert_eq!(captured_logs[0].level, Level::Info);
  525. });
  526. }
  527. #[test]
  528. fn test_display_hint_default() {
  529. testing_logger::setup();
  530. let (mut len, mut input) = new_log(3).unwrap();
  531. len += "default hint: ".write(&mut input[len..]).unwrap();
  532. len += DisplayHint::Default.write(&mut input[len..]).unwrap();
  533. 14.write(&mut input[len..]).unwrap();
  534. let logger = logger();
  535. let _ = log_buf(&input, logger);
  536. testing_logger::validate(|captured_logs| {
  537. assert_eq!(captured_logs.len(), 1);
  538. assert_eq!(captured_logs[0].body, "default hint: 14");
  539. assert_eq!(captured_logs[0].level, Level::Info);
  540. });
  541. }
  542. #[test]
  543. fn test_display_hint_lower_hex() {
  544. testing_logger::setup();
  545. let (mut len, mut input) = new_log(3).unwrap();
  546. len += "lower hex: ".write(&mut input[len..]).unwrap();
  547. len += DisplayHint::LowerHex.write(&mut input[len..]).unwrap();
  548. 200.write(&mut input[len..]).unwrap();
  549. let logger = logger();
  550. let _ = log_buf(&input, logger);
  551. testing_logger::validate(|captured_logs| {
  552. assert_eq!(captured_logs.len(), 1);
  553. assert_eq!(captured_logs[0].body, "lower hex: c8");
  554. assert_eq!(captured_logs[0].level, Level::Info);
  555. });
  556. }
  557. #[test]
  558. fn test_display_hint_upper_hex() {
  559. testing_logger::setup();
  560. let (mut len, mut input) = new_log(3).unwrap();
  561. len += "upper hex: ".write(&mut input[len..]).unwrap();
  562. len += DisplayHint::UpperHex.write(&mut input[len..]).unwrap();
  563. 200.write(&mut input[len..]).unwrap();
  564. let logger = logger();
  565. let _ = log_buf(&input, logger);
  566. testing_logger::validate(|captured_logs| {
  567. assert_eq!(captured_logs.len(), 1);
  568. assert_eq!(captured_logs[0].body, "upper hex: C8");
  569. assert_eq!(captured_logs[0].level, Level::Info);
  570. });
  571. }
  572. #[test]
  573. fn test_display_hint_ipv4() {
  574. testing_logger::setup();
  575. let (mut len, mut input) = new_log(3).unwrap();
  576. len += "ipv4: ".write(&mut input[len..]).unwrap();
  577. len += DisplayHint::Ipv4.write(&mut input[len..]).unwrap();
  578. // 10.0.0.1 as u32
  579. 167772161u32.write(&mut input[len..]).unwrap();
  580. let logger = logger();
  581. let _ = log_buf(&input, logger);
  582. testing_logger::validate(|captured_logs| {
  583. assert_eq!(captured_logs.len(), 1);
  584. assert_eq!(captured_logs[0].body, "ipv4: 10.0.0.1");
  585. assert_eq!(captured_logs[0].level, Level::Info);
  586. });
  587. }
  588. #[test]
  589. fn test_display_hint_ipv6_arr_u8_len_16() {
  590. testing_logger::setup();
  591. let (mut len, mut input) = new_log(3).unwrap();
  592. len += "ipv6: ".write(&mut input[len..]).unwrap();
  593. len += DisplayHint::Ipv6.write(&mut input[len..]).unwrap();
  594. // 2001:db8::1:1 as byte array
  595. let ipv6_arr: [u8; 16] = [
  596. 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  597. 0x00, 0x01,
  598. ];
  599. ipv6_arr.write(&mut input[len..]).unwrap();
  600. let logger = logger();
  601. let _ = log_buf(&input, logger);
  602. testing_logger::validate(|captured_logs| {
  603. assert_eq!(captured_logs.len(), 1);
  604. assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
  605. assert_eq!(captured_logs[0].level, Level::Info);
  606. });
  607. }
  608. #[test]
  609. fn test_display_hint_ipv6_arr_u16_len_8() {
  610. testing_logger::setup();
  611. let (mut len, mut input) = new_log(3).unwrap();
  612. len += "ipv6: ".write(&mut input[len..]).unwrap();
  613. len += DisplayHint::Ipv6.write(&mut input[len..]).unwrap();
  614. // 2001:db8::1:1 as u16 array
  615. let ipv6_arr: [u16; 8] = [
  616. 0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001,
  617. ];
  618. ipv6_arr.write(&mut input[len..]).unwrap();
  619. let logger = logger();
  620. let _ = log_buf(&input, logger);
  621. testing_logger::validate(|captured_logs| {
  622. assert_eq!(captured_logs.len(), 1);
  623. assert_eq!(captured_logs[0].body, "ipv6: 2001:db8::1:1");
  624. assert_eq!(captured_logs[0].level, Level::Info);
  625. });
  626. }
  627. #[test]
  628. fn test_display_hint_lower_mac() {
  629. testing_logger::setup();
  630. let (mut len, mut input) = new_log(3).unwrap();
  631. len += "mac: ".write(&mut input[len..]).unwrap();
  632. len += DisplayHint::LowerMac.write(&mut input[len..]).unwrap();
  633. // 00:00:5e:00:53:af as byte array
  634. let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf];
  635. mac_arr.write(&mut input[len..]).unwrap();
  636. let logger = logger();
  637. let _ = log_buf(&input, logger);
  638. testing_logger::validate(|captured_logs| {
  639. assert_eq!(captured_logs.len(), 1);
  640. assert_eq!(captured_logs[0].body, "mac: 00:00:5e:00:53:af");
  641. assert_eq!(captured_logs[0].level, Level::Info);
  642. });
  643. }
  644. #[test]
  645. fn test_display_hint_upper_mac() {
  646. testing_logger::setup();
  647. let (mut len, mut input) = new_log(3).unwrap();
  648. len += "mac: ".write(&mut input[len..]).unwrap();
  649. len += DisplayHint::UpperMac.write(&mut input[len..]).unwrap();
  650. // 00:00:5E:00:53:AF as byte array
  651. let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf];
  652. mac_arr.write(&mut input[len..]).unwrap();
  653. let logger = logger();
  654. let _ = log_buf(&input, logger);
  655. testing_logger::validate(|captured_logs| {
  656. assert_eq!(captured_logs.len(), 1);
  657. assert_eq!(captured_logs[0].body, "mac: 00:00:5E:00:53:AF");
  658. assert_eq!(captured_logs[0].level, Level::Info);
  659. });
  660. }
  661. }