log.rs 3.4 KB

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