From 90faac2a3a7ee4e416badacb9795bfac7abd8615 Mon Sep 17 00:00:00 2001 From: Michal Rostecki Date: Fri, 30 Sep 2022 12:52:54 +0200 Subject: [PATCH] aya-log: Add `*max_level_*` filter features Add the following features for configuring the maximum log level available: * `max_level_off` * `max_level_error` * `max_level_warn` * `max_level_info` * `max_level_debug` * `max_level_trace` * `release_max_level_off` * `release_max_level_error` * `release_max_level_warn` * `release_max_level_info` * `release_max_level_debug` * `release_max_level_trace` Log invocations at disabled level will be skipped, which is especially beneficial for eBPF programs which are not going to send unneceessary logs through perf buffers. Features with `release_` prefix are used only in release builds. Those features have to applied on the userspace and eBPF crate separately. The correct thing to do is to set them on the same level. In case when userspace has higher maximum log level, it's not going to recieve the logs beyond the filter in eBPF crate. In the opposite situation, when eBPF crate has higher maximum level, it's going to waste cycles on sending logs through perf buffer, while they are not going to be displayed in the userspace. Signed-off-by: Michal Rostecki --- aya-log-ebpf-macros/Cargo.toml | 18 ++++++++++- aya-log-ebpf-macros/src/expand.rs | 25 ++++++++++++--- aya-log-ebpf-macros/src/lib.rs | 53 +++++++++++++++++++++++++++++++ aya-log/Cargo.toml | 15 +++++++++ bpf/aya-log-ebpf/Cargo.toml | 15 +++++++++ 5 files changed, 120 insertions(+), 6 deletions(-) diff --git a/aya-log-ebpf-macros/Cargo.toml b/aya-log-ebpf-macros/Cargo.toml index 5396ed16..81be5006 100644 --- a/aya-log-ebpf-macros/Cargo.toml +++ b/aya-log-ebpf-macros/Cargo.toml @@ -8,7 +8,23 @@ aya-log-common = { path = "../aya-log-common" } aya-log-parser = { path = "../aya-log-parser" } proc-macro2 = "1.0" quote = "1.0" -syn = "1.0" +syn = { version = "1.0", features = ["extra-traits"] } +cfg-if = "1.0" + +[features] +max_level_off = [] +max_level_error = [] +max_level_warn = [] +max_level_info = [] +max_level_debug = [] +max_level_trace = [] + +release_max_level_off = [] +release_max_level_error = [] +release_max_level_warn = [] +release_max_level_info = [] +release_max_level_debug = [] +release_max_level_trace = [] [lib] proc-macro = true diff --git a/aya-log-ebpf-macros/src/expand.rs b/aya-log-ebpf-macros/src/expand.rs index 2aeb9ca8..69cb8cae 100644 --- a/aya-log-ebpf-macros/src/expand.rs +++ b/aya-log-ebpf-macros/src/expand.rs @@ -10,6 +10,8 @@ use syn::{ use aya_log_common::DisplayHint; use aya_log_parser::{parse, Fragment}; +use crate::{LevelFilter, MAX_LEVEL}; + pub(crate) struct LogArgs { pub(crate) ctx: Expr, pub(crate) target: Option, @@ -90,10 +92,23 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result quote! { #t }, None => quote! { module_path!() }, }; - let lvl: TokenStream = if let Some(l) = level { - l - } else if let Some(l) = args.level { - quote! { #l } + let level: TokenStream = if let Some(level) = level { + // Level was chosen by calling concrete macros like error!, warn!, etc. + level + } else if let Some(level) = args.level { + // Level was chosen by passing an argument to the log! macro. + // We need to apply the max log level filter here. + let level_str = format!("{:?}", level); + if (level_str.contains("Error") && LevelFilter::Error > MAX_LEVEL) + || (level_str.contains("Warn") && LevelFilter::Warn > MAX_LEVEL) + || (level_str.contains("Info") && LevelFilter::Info > MAX_LEVEL) + || (level_str.contains("Debug") && LevelFilter::Debug > MAX_LEVEL) + || (level_str.contains("Trace") && LevelFilter::Trace > MAX_LEVEL) + { + return Ok(TokenStream::new()); + } + + quote! { #level } } else { return Err(Error::new( args.format_string.span(), @@ -140,7 +155,7 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result TokenStream { let args = parse_macro_input!(args as expand::LogArgs); @@ -13,6 +51,9 @@ pub fn log(args: TokenStream) -> TokenStream { #[proc_macro] pub fn error(args: TokenStream) -> TokenStream { + if LevelFilter::Error > MAX_LEVEL { + return TokenStream::new(); + } let args = parse_macro_input!(args as expand::LogArgs); expand::error(args) .unwrap_or_else(|err| err.to_compile_error()) @@ -21,6 +62,9 @@ pub fn error(args: TokenStream) -> TokenStream { #[proc_macro] pub fn warn(args: TokenStream) -> TokenStream { + if LevelFilter::Warn > MAX_LEVEL { + return TokenStream::new(); + } let args = parse_macro_input!(args as expand::LogArgs); expand::warn(args) .unwrap_or_else(|err| err.to_compile_error()) @@ -29,6 +73,9 @@ pub fn warn(args: TokenStream) -> TokenStream { #[proc_macro] pub fn info(args: TokenStream) -> TokenStream { + if LevelFilter::Info > MAX_LEVEL { + return TokenStream::new(); + } let args = parse_macro_input!(args as expand::LogArgs); expand::info(args) .unwrap_or_else(|err| err.to_compile_error()) @@ -37,6 +84,9 @@ pub fn info(args: TokenStream) -> TokenStream { #[proc_macro] pub fn debug(args: TokenStream) -> TokenStream { + if LevelFilter::Debug > MAX_LEVEL { + return TokenStream::new(); + } let args = parse_macro_input!(args as expand::LogArgs); expand::debug(args) .unwrap_or_else(|err| err.to_compile_error()) @@ -45,6 +95,9 @@ pub fn debug(args: TokenStream) -> TokenStream { #[proc_macro] pub fn trace(args: TokenStream) -> TokenStream { + if LevelFilter::Trace > MAX_LEVEL { + return TokenStream::new(); + } let args = parse_macro_input!(args as expand::LogArgs); expand::trace(args) .unwrap_or_else(|err| err.to_compile_error()) diff --git a/aya-log/Cargo.toml b/aya-log/Cargo.toml index 97424297..2b53d30e 100644 --- a/aya-log/Cargo.toml +++ b/aya-log/Cargo.toml @@ -22,5 +22,20 @@ tokio = { version = "1.2.0" } env_logger = "0.9" testing_logger = "0.1.1" +[features] +max_level_off = ["log/max_level_off"] +max_level_error = ["log/max_level_error"] +max_level_warn = ["log/max_level_warn"] +max_level_info = ["log/max_level_info"] +max_level_debug = ["log/max_level_debug"] +max_level_trace = ["log/max_level_trace"] + +release_max_level_off = ["log/release_max_level_off"] +release_max_level_error = ["log/release_max_level_error"] +release_max_level_warn = ["log/release_max_level_warn"] +release_max_level_info = ["log/release_max_level_info"] +release_max_level_debug = ["log/release_max_level_debug"] +release_max_level_trace = ["log/release_max_level_trace"] + [lib] path = "src/lib.rs" diff --git a/bpf/aya-log-ebpf/Cargo.toml b/bpf/aya-log-ebpf/Cargo.toml index a0a2693d..5945645a 100644 --- a/bpf/aya-log-ebpf/Cargo.toml +++ b/bpf/aya-log-ebpf/Cargo.toml @@ -8,5 +8,20 @@ aya-bpf = { path = "../aya-bpf" } aya-log-common = { path = "../../aya-log-common" } aya-log-ebpf-macros = { path = "../../aya-log-ebpf-macros" } +[features] +max_level_off = ["aya-log-ebpf-macros/max_level_off"] +max_level_error = ["aya-log-ebpf-macros/max_level_error"] +max_level_warn = ["aya-log-ebpf-macros/max_level_warn"] +max_level_info = ["aya-log-ebpf-macros/max_level_info"] +max_level_debug = ["aya-log-ebpf-macros/max_level_debug"] +max_level_trace = ["aya-log-ebpf-macros/max_level_trace"] + +release_max_level_off = ["aya-log-ebpf-macros/release_max_level_off"] +release_max_level_error = ["aya-log-ebpf-macros/release_max_level_error"] +release_max_level_warn = ["aya-log-ebpf-macros/release_max_level_warn"] +release_max_level_info = ["aya-log-ebpf-macros/release_max_level_info"] +release_max_level_debug = ["aya-log-ebpf-macros/release_max_level_debug"] +release_max_level_trace = ["aya-log-ebpf-macros/release_max_level_trace"] + [lib] path = "src/lib.rs"