Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 16 additions & 39 deletions aya-log-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ use core::{

use num_enum::IntoPrimitive;

pub const LOG_BUF_CAPACITY: usize = 8192;

pub const LOG_FIELDS: usize = 6;

pub type LogValueLength = u16;
Expand Down Expand Up @@ -173,17 +171,12 @@ pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Option<NonZeroUsiz
Err(TryFromIntError { .. }) => None,
}?;
let mut size = 0;
macro_rules! copy_from_slice {
($value:expr) => {{
let buf = buf.get_mut(size..)?;
let buf = buf.get_mut(..$value.len())?;
buf.copy_from_slice($value);
size += $value.len();
}};
for slice in [&[tag][..], &wire_len.to_ne_bytes()[..], value] {
let buf = buf.get_mut(size..)?;
let buf = buf.get_mut(..slice.len())?;
buf.copy_from_slice(slice);
size += slice.len();
}
copy_from_slice!(&[tag]);
copy_from_slice!(&wire_len.to_ne_bytes());
copy_from_slice!(value);
NonZeroUsize::new(size)
}

Expand Down Expand Up @@ -320,33 +313,17 @@ pub fn write_record_header(
) -> Option<NonZeroUsize> {
let level: u8 = level.into();
let mut size = 0;
macro_rules! write {
($tag:expr, $value:expr) => {{
let buf = buf.get_mut(size..)?;
let len = write($tag.into(), $value, buf)?;
size += len.get();
}};
for (tag, value) in [
(RecordField::Target, target.as_bytes()),
(RecordField::Level, &level.to_ne_bytes()),
(RecordField::Module, module.as_bytes()),
(RecordField::File, file.as_bytes()),
(RecordField::Line, &line.to_ne_bytes()),
(RecordField::NumArgs, &num_args.to_ne_bytes()),
] {
let buf = buf.get_mut(size..)?;
let len = write(tag.into(), value, buf)?;
size += len.get();
}
write!(RecordField::Target, target.as_bytes());
write!(RecordField::Level, &level.to_ne_bytes());
write!(RecordField::Module, module.as_bytes());
write!(RecordField::File, file.as_bytes());
write!(RecordField::Line, &line.to_ne_bytes());
write!(RecordField::NumArgs, &num_args.to_ne_bytes());
NonZeroUsize::new(size)
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn log_value_length_sufficient() {
assert!(
LOG_BUF_CAPACITY <= LogValueLength::MAX.into(),
"{} > {}",
LOG_BUF_CAPACITY,
LogValueLength::MAX
);
}
}
58 changes: 33 additions & 25 deletions aya-log-ebpf-macros/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,27 @@ impl Parse for LogArgs {
}

pub(crate) fn log(args: LogArgs, level: Option<TokenStream>) -> Result<TokenStream> {
let ctx = args.ctx;
let target = match args.target {
let LogArgs {
ctx,
target,
level: level_expr,
format_string,
formatting_args,
} = args;
let target = match target {
Some(t) => quote! { #t },
None => quote! { module_path!() },
};
let lvl: TokenStream = if let Some(l) = level {
l
} else if let Some(l) = args.level {
quote! { #l }
} else {
return Err(Error::new(
args.format_string.span(),
"missing `level` argument: try passing an `aya_log_ebpf::Level` value",
));
let level = match level {
Some(l) => l,
None => {
let l = level_expr.ok_or(Error::new(
format_string.span(),
"missing `level` argument: try passing an `aya_log_ebpf::Level` value",
))?;
quote! { #l }
}
};
let format_string = args.format_string;

let format_string_val = format_string.value();
let fragments = parse(&format_string_val).map_err(|e| {
Expand All @@ -101,7 +106,7 @@ pub(crate) fn log(args: LogArgs, level: Option<TokenStream>) -> Result<TokenStre
match fragment {
Fragment::Literal(s) => values.push(quote!(#s)),
Fragment::Parameter(p) => {
let arg = match args.formatting_args {
let arg = match formatting_args {
Some(ref args) => args[arg_i].clone(),
None => return Err(Error::new(format_string.span(), "no arguments provided")),
};
Expand Down Expand Up @@ -141,33 +146,36 @@ pub(crate) fn log(args: LogArgs, level: Option<TokenStream>) -> Result<TokenStre

let num_args = values.len();
let values_iter = values.iter();
let buf = Ident::new("buf", Span::mixed_site());
let size = Ident::new("size", Span::mixed_site());
let len = Ident::new("len", Span::mixed_site());
let slice = Ident::new("slice", Span::mixed_site());
let record = Ident::new("record", Span::mixed_site());
Ok(quote! {
match ::aya_log_ebpf::AYA_LOG_BUF.get_ptr_mut(0).and_then(|ptr| unsafe { ptr.as_mut() }) {
match ::aya_log_ebpf::macro_support::AYA_LOG_BUF.get_ptr_mut(0).and_then(|ptr| unsafe { ptr.as_mut() }) {
None => {},
Some(::aya_log_ebpf::LogBuf { buf }) => {
Some(::aya_log_ebpf::macro_support::LogBuf { buf: #buf }) => {
// Silence unused variable warning; we may need ctx in the future.
let _ = #ctx;
let _: Option<()> = (|| {
let #size = ::aya_log_ebpf::write_record_header(
buf,
let #size = ::aya_log_ebpf::macro_support::write_record_header(
#buf,
#target,
#lvl,
#level,
module_path!(),
file!(),
line!(),
#num_args,
)?;
let mut #size = #size.get();
#(
let #slice = buf.get_mut(#size..)?;
let #len = ::aya_log_ebpf::WriteToBuf::write(#values_iter, #slice)?;
#size += #len.get();
{
let #buf = #buf.get_mut(#size..)?;
let #len = ::aya_log_ebpf::macro_support::WriteToBuf::write(#values_iter, #buf)?;
#size += #len.get();
}
)*
let #record = buf.get(..#size)?;
::aya_log_ebpf::AYA_LOGS.output(#ctx, #record, 0);
Some(())
let #record = #buf.get(..#size)?;
Result::<_, i64>::ok(::aya_log_ebpf::macro_support::AYA_LOGS.output(#record, 0))
})();
}
}
Expand Down
9 changes: 9 additions & 0 deletions aya-log/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Breaking Changes

- The implementation is now backed by a ring buffer rather than a perf event array. This should
improve performance but increases the minimum supported kernel version to 5.8.

- Drop the built-in `tokio` dependency. Users must now BYOR (bring your own runtime).

## v0.2.1 (2024-10-09)

### Chore
Expand Down
5 changes: 2 additions & 3 deletions aya-log/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@ rust-version.workspace = true
workspace = true

[dependencies]
aya = { path = "../aya", version = "^0.13.1", features = ["async_tokio"] }
aya = { path = "../aya", version = "^0.13.1", default-features = false }
aya-log-common = { path = "../aya-log-common", version = "^0.1.15", default-features = false }
bytes = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt"] }

[dev-dependencies]
env_logger = { workspace = true }
testing_logger = { workspace = true }
tokio = { workspace = true, features = ["net", "rt"] }

[lib]
path = "src/lib.rs"
10 changes: 9 additions & 1 deletion aya-log/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ use aya_log::EbpfLogger;
env_logger::init();

// Will log using the default logger, which is TermLogger in this case
EbpfLogger::init(&mut bpf).unwrap();
let logger = EbpfLogger::init(&mut bpf).unwrap();
let mut logger = tokio::io::unix::AsyncFd::with_interest(logger, tokio::io::Interest::READABLE).unwrap();
tokio::task::spawn(async move {
loop {
let mut guard = logger.readable_mut().await.unwrap();
guard.get_inner_mut().flush();
guard.clear_ready();
}
});
```

### eBPF code
Expand Down
Loading
Loading