log.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. use std::{
  2. borrow::Cow,
  3. sync::{Arc, Mutex},
  4. };
  5. use aya::{programs::UProbe, Bpf};
  6. use aya_log::EbpfLogger;
  7. use log::{Level, Log, Record};
  8. use test_log::test;
  9. #[no_mangle]
  10. #[inline(never)]
  11. pub extern "C" fn trigger_ebpf_program() {
  12. core::hint::black_box(trigger_ebpf_program);
  13. }
  14. struct TestingLogger<F> {
  15. log: F,
  16. }
  17. impl<F: Send + Sync + Fn(&Record)> Log for TestingLogger<F> {
  18. fn enabled(&self, _metadata: &log::Metadata) -> bool {
  19. true
  20. }
  21. fn flush(&self) {}
  22. fn log(&self, record: &Record) {
  23. let Self { log } = self;
  24. log(record);
  25. }
  26. }
  27. #[derive(Debug, PartialEq)]
  28. struct CapturedLog<'a> {
  29. pub body: Cow<'a, str>,
  30. pub level: Level,
  31. pub target: Cow<'a, str>,
  32. }
  33. #[test(tokio::test)]
  34. async fn log() {
  35. let mut bpf = Bpf::load(crate::LOG).unwrap();
  36. let captured_logs = Arc::new(Mutex::new(Vec::new()));
  37. {
  38. let captured_logs = captured_logs.clone();
  39. EbpfLogger::init_with_logger(
  40. &mut bpf,
  41. TestingLogger {
  42. log: move |record: &Record| {
  43. let mut logs = captured_logs.lock().unwrap();
  44. logs.push(CapturedLog {
  45. body: format!("{}", record.args()).into(),
  46. level: record.level(),
  47. target: record.target().to_string().into(),
  48. });
  49. },
  50. },
  51. )
  52. .unwrap();
  53. }
  54. let prog: &mut UProbe = bpf.program_mut("test_log").unwrap().try_into().unwrap();
  55. prog.load().unwrap();
  56. prog.attach(Some("trigger_ebpf_program"), 0, "/proc/self/exe", None)
  57. .unwrap();
  58. // Call the function that the uprobe is attached to, so it starts logging.
  59. trigger_ebpf_program();
  60. let mut logs = 0;
  61. let records = loop {
  62. tokio::time::sleep(std::time::Duration::from_millis(100)).await;
  63. let records = captured_logs.lock().unwrap();
  64. let len = records.len();
  65. if len == 0 {
  66. continue;
  67. }
  68. if len == logs {
  69. break records;
  70. }
  71. logs = len;
  72. };
  73. let mut records = records.iter();
  74. assert_eq!(
  75. records.next(),
  76. Some(&CapturedLog {
  77. body: "Hello from eBPF!".into(),
  78. level: Level::Debug,
  79. target: "log".into(),
  80. }),
  81. );
  82. assert_eq!(
  83. records.next(),
  84. Some(&CapturedLog {
  85. body: "69, 420, wao, 77616f".into(),
  86. level: Level::Error,
  87. target: "log".into(),
  88. })
  89. );
  90. assert_eq!(
  91. records.next(),
  92. Some(&CapturedLog {
  93. body: "ipv4: 10.0.0.1, ipv6: 2001:db8::1".into(),
  94. level: Level::Info,
  95. target: "log".into(),
  96. })
  97. );
  98. assert_eq!(
  99. records.next(),
  100. Some(&CapturedLog {
  101. body: "mac lc: 04:20:06:09:00:40, mac uc: 04:20:06:09:00:40".into(),
  102. level: Level::Trace,
  103. target: "log".into(),
  104. })
  105. );
  106. assert_eq!(
  107. records.next(),
  108. Some(&CapturedLog {
  109. body: "hex lc: 2f, hex uc: 2F".into(),
  110. level: Level::Warn,
  111. target: "log".into(),
  112. })
  113. );
  114. assert_eq!(
  115. records.next(),
  116. Some(&CapturedLog {
  117. body: "hex lc: deadbeef, hex uc: DEADBEEF".into(),
  118. level: Level::Debug,
  119. target: "log".into(),
  120. })
  121. );
  122. assert_eq!(
  123. records.next(),
  124. Some(&CapturedLog {
  125. body: "42 43 44 45".into(),
  126. level: Level::Debug,
  127. target: "log".into(),
  128. })
  129. );
  130. assert_eq!(records.next(), None);
  131. }