lib.rs 27 KB

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