4
0

log.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. use std::sync::{Arc, LockResult, Mutex, MutexGuard};
  2. use aya::{include_bytes_aligned, programs::UProbe, Bpf};
  3. use aya_log::BpfLogger;
  4. use log::{Level, Log, Record};
  5. use tokio::time::{sleep, Duration};
  6. const MAX_ATTEMPTS: usize = 10;
  7. const TIMEOUT_MS: u64 = 10;
  8. #[no_mangle]
  9. #[inline(never)]
  10. pub extern "C" fn trigger_ebpf_program() {}
  11. struct CapturedLogs(Arc<Mutex<Vec<CapturedLog>>>);
  12. impl CapturedLogs {
  13. fn with_capacity(capacity: usize) -> Self {
  14. Self(Arc::new(Mutex::new(Vec::with_capacity(capacity))))
  15. }
  16. fn clone(&self) -> Self {
  17. Self(self.0.clone())
  18. }
  19. fn lock(&self) -> LockResult<MutexGuard<'_, Vec<CapturedLog>>> {
  20. self.0.lock()
  21. }
  22. async fn wait_expected_len(&self, expected_len: usize) {
  23. for _ in 0..MAX_ATTEMPTS {
  24. {
  25. let captured_logs = self.0.lock().expect("Failed to lock captured logs");
  26. if captured_logs.len() == expected_len {
  27. return;
  28. }
  29. }
  30. sleep(Duration::from_millis(TIMEOUT_MS)).await;
  31. }
  32. panic!(
  33. "Expected {} captured logs, but got {}",
  34. expected_len,
  35. self.0.lock().unwrap().len()
  36. );
  37. }
  38. }
  39. struct CapturedLog {
  40. pub body: String,
  41. pub level: Level,
  42. pub target: String,
  43. }
  44. struct TestingLogger {
  45. captured_logs: CapturedLogs,
  46. }
  47. impl TestingLogger {
  48. pub fn with_capacity(capacity: usize) -> (Self, CapturedLogs) {
  49. let captured_logs = CapturedLogs::with_capacity(capacity);
  50. (
  51. Self {
  52. captured_logs: captured_logs.clone(),
  53. },
  54. captured_logs,
  55. )
  56. }
  57. }
  58. impl Log for TestingLogger {
  59. fn enabled(&self, _metadata: &log::Metadata) -> bool {
  60. true
  61. }
  62. fn flush(&self) {}
  63. fn log(&self, record: &Record) {
  64. let captured_record = CapturedLog {
  65. body: format!("{}", record.args()),
  66. level: record.level(),
  67. target: record.target().to_string(),
  68. };
  69. self.captured_logs
  70. .lock()
  71. .expect("Failed to acquire a lock for storing a log")
  72. .push(captured_record);
  73. }
  74. }
  75. #[tokio::test]
  76. async fn log() {
  77. let bytes = include_bytes_aligned!("../../../target/bpfel-unknown-none/release/log");
  78. let mut bpf = Bpf::load(bytes).unwrap();
  79. let (logger, captured_logs) = TestingLogger::with_capacity(5);
  80. BpfLogger::init_with_logger(&mut bpf, logger).unwrap();
  81. let prog: &mut UProbe = bpf.program_mut("test_log").unwrap().try_into().unwrap();
  82. prog.load().unwrap();
  83. prog.attach(Some("trigger_ebpf_program"), 0, "/proc/self/exe", None)
  84. .unwrap();
  85. // Call the function that the uprobe is attached to, so it starts logging.
  86. trigger_ebpf_program();
  87. captured_logs.wait_expected_len(6).await;
  88. let records = captured_logs
  89. .lock()
  90. .expect("Failed to acquire a lock for reading logs");
  91. assert_eq!(records.len(), 6);
  92. assert_eq!(records[0].body, "Hello from eBPF!");
  93. assert_eq!(records[0].level, Level::Debug);
  94. assert_eq!(records[0].target, "log");
  95. assert_eq!(records[1].body, "69, 420, wao");
  96. assert_eq!(records[1].level, Level::Error);
  97. assert_eq!(records[1].target, "log");
  98. assert_eq!(records[2].body, "ipv4: 10.0.0.1, ipv6: 2001:db8::1");
  99. assert_eq!(records[2].level, Level::Info);
  100. assert_eq!(records[2].target, "log");
  101. assert_eq!(
  102. records[3].body,
  103. "mac lc: 04:20:06:09:00:40, mac uc: 04:20:06:09:00:40"
  104. );
  105. assert_eq!(records[3].level, Level::Trace);
  106. assert_eq!(records[3].target, "log");
  107. assert_eq!(records[4].body, "hex lc: 2f, hex uc: 2F");
  108. assert_eq!(records[4].level, Level::Warn);
  109. assert_eq!(records[4].target, "log");
  110. assert_eq!(records[5].body, "hex lc: deadbeef, hex uc: DEADBEEF");
  111. assert_eq!(records[5].level, Level::Debug);
  112. assert_eq!(records[5].target, "log");
  113. }