4
0

lib.rs 27 KB

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