Skip to content

Commit f84e5a7

Browse files
authored
Add min_log_level config (#43)
* Add min_log_level config * Address comments
1 parent 8a0a97a commit f84e5a7

File tree

3 files changed

+87
-12
lines changed

3 files changed

+87
-12
lines changed

src/bridges/tracing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1378,7 +1378,7 @@ mod tests {
13781378

13791379
let console_options = ConsoleOptions {
13801380
target: Target::Pipe(output.clone()),
1381-
..ConsoleOptions::default()
1381+
..ConsoleOptions::default().with_min_log_level(Level::TRACE)
13821382
};
13831383

13841384
let handler = crate::configure()

src/config.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use opentelemetry_sdk::{
1515
use regex::Regex;
1616

1717
use crate::ConfigureError;
18+
use tracing::Level;
1819

1920
/// Whether to send logs to Logfire.
2021
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
@@ -71,6 +72,8 @@ pub struct ConsoleOptions {
7172
pub(crate) target: Target,
7273
/// Whether to include timestamps in the console output.
7374
pub include_timestamps: bool,
75+
/// The minimum log level to show in the console.
76+
pub min_log_level: Level,
7477
// TODO: support the below configuration options (inherited from Python SDK)
7578

7679
// /// Whether to show colors in the console.
@@ -83,8 +86,6 @@ pub struct ConsoleOptions {
8386
// ///
8487
// /// It includes the filename, log level, and line number.
8588
// verbose: bool,
86-
// /// The minimum log level to show in the console.
87-
// min_log_level: Level,
8889
// /// Whether to print the URL of the Logfire project after initialization.
8990
// show_project_link: bool,
9091
}
@@ -96,7 +97,7 @@ impl Default for ConsoleOptions {
9697
// span_style: SpanStyle::default(),
9798
// include_tags: true,
9899
// verbose: false,
99-
// min_log_level: Level::INFO,
100+
min_log_level: Level::INFO,
100101
// show_project_link: true,
101102
target: Target::default(),
102103
include_timestamps: true,
@@ -120,6 +121,13 @@ impl ConsoleOptions {
120121
self.include_timestamps = include;
121122
self
122123
}
124+
125+
/// Set the minimum log level to show in the console.
126+
#[must_use]
127+
pub fn with_min_log_level(mut self, min_log_level: Level) -> Self {
128+
self.min_log_level = min_log_level;
129+
self
130+
}
123131
}
124132

125133
/// Whether to show colors in the console.
@@ -383,4 +391,13 @@ mod tests {
383391
let options = super::ConsoleOptions::default().with_include_timestamps(true);
384392
assert!(options.include_timestamps);
385393
}
394+
395+
#[test]
396+
fn test_console_option_with_min_log_level() {
397+
let console_options = super::ConsoleOptions::default();
398+
assert_eq!(console_options.min_log_level, tracing::Level::INFO);
399+
let console_options =
400+
super::ConsoleOptions::default().with_min_log_level(tracing::Level::DEBUG);
401+
assert_eq!(console_options.min_log_level, tracing::Level::DEBUG);
402+
}
386403
}

src/internal/exporters/console.rs

+66-8
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,11 @@ impl ConsoleWriter {
125125
msg = Some(kv.value.as_str());
126126
}
127127
"logfire.level_num" => {
128-
if let Value::I64(val) = kv.value {
129-
level = Some(val);
128+
if let Value::I64(level_num) = kv.value {
129+
if level_num < level_to_level_number(self.options.min_log_level) {
130+
return Ok(());
131+
}
132+
level = Some(level_num);
130133
}
131134
}
132135
"code.namespace" => target = Some(kv.value.as_str()),
@@ -192,6 +195,10 @@ impl ConsoleWriter {
192195
w: &mut W,
193196
) -> io::Result<()> {
194197
let level = level_to_level_number(*event.metadata().level());
198+
// Filter out event below the minimum log level
199+
if level < level_to_level_number(self.options.min_log_level) {
200+
return Ok(());
201+
}
195202
let target = event.metadata().module_path();
196203

197204
let mut visitor = FieldsVisitor {
@@ -251,8 +258,11 @@ impl ConsoleWriter {
251258
msg = Some(kv.value.as_str());
252259
}
253260
"logfire.level_num" => {
254-
if let Value::I64(val) = kv.value {
255-
level = Some(val);
261+
if let Value::I64(level_num) = kv.value {
262+
if level_num < level_to_level_number(self.options.min_log_level) {
263+
return Ok(());
264+
}
265+
level = Some(level_num);
256266
}
257267
}
258268
"code.namespace" => target = Some(kv.value.as_str()),
@@ -358,7 +368,9 @@ mod tests {
358368
fn test_print_to_console() {
359369
let output = Arc::new(Mutex::new(Vec::new()));
360370

361-
let console_options = ConsoleOptions::default().with_target(Target::Pipe(output.clone()));
371+
let console_options = ConsoleOptions::default()
372+
.with_target(Target::Pipe(output.clone()))
373+
.with_min_log_level(Level::TRACE);
362374

363375
let handler = crate::configure()
364376
.local()
@@ -395,7 +407,7 @@ mod tests {
395407
1970-01-01T00:00:00.000002Z DEBUG logfire::internal::exporters::console::tests debug span
396408
1970-01-01T00:00:00.000003Z DEBUG logfire::internal::exporters::console::tests debug span with explicit parent
397409
1970-01-01T00:00:00.000004Z INFO logfire::internal::exporters::console::tests hello world log
398-
[2m1970-01-01T00:00:00.000005Z[0m[31m ERROR[0m [2;3mlogfire[0m [1mpanic: oh no![0m [3mlocation[0m=src/internal/exporters/console.rs:381:17, [3mbacktrace[0m=disabled backtrace
410+
[2m1970-01-01T00:00:00.000005Z[0m[31m ERROR[0m [2;3mlogfire[0m [1mpanic: oh no![0m [3mlocation[0m=src/internal/exporters/console.rs:393:17, [3mbacktrace[0m=disabled backtrace
399411
");
400412
}
401413

@@ -405,7 +417,8 @@ mod tests {
405417

406418
let console_options = ConsoleOptions::default()
407419
.with_target(Target::Pipe(output.clone()))
408-
.with_include_timestamps(false);
420+
.with_include_timestamps(false)
421+
.with_min_log_level(Level::TRACE);
409422

410423
let handler = crate::configure()
411424
.local()
@@ -442,7 +455,52 @@ mod tests {
442455
 DEBUG logfire::internal::exporters::console::tests debug span
443456
 DEBUG logfire::internal::exporters::console::tests debug span with explicit parent
444457
 INFO logfire::internal::exporters::console::tests hello world log
445-
 ERROR logfire panic: oh no! location=src/internal/exporters/console.rs:428:17, backtrace=disabled backtrace
458+
 ERROR logfire panic: oh no! location=src/internal/exporters/console.rs:441:17, backtrace=disabled backtrace
459+
");
460+
}
461+
462+
#[test]
463+
fn test_print_to_console_with_min_log_level() {
464+
let output = Arc::new(Mutex::new(Vec::new()));
465+
466+
let console_options = ConsoleOptions::default()
467+
.with_target(Target::Pipe(output.clone()))
468+
.with_min_log_level(Level::INFO);
469+
470+
let handler = crate::configure()
471+
.local()
472+
.send_to_logfire(false)
473+
.with_console(Some(console_options))
474+
.install_panic_handler()
475+
.with_default_level_filter(LevelFilter::TRACE)
476+
.finish()
477+
.unwrap();
478+
479+
let guard = set_local_logfire(handler);
480+
481+
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
482+
tracing::subscriber::with_default(guard.subscriber().clone(), || {
483+
let root = crate::span!("root span").entered();
484+
let _ = crate::span!("hello world span").entered();
485+
let _ = crate::span!(level: Level::DEBUG, "debug span");
486+
let _ = crate::span!(parent: &root, level: Level::DEBUG, "debug span with explicit parent");
487+
crate::info!("hello world log");
488+
panic!("oh no!");
489+
});
490+
}))
491+
.unwrap_err();
492+
493+
guard.shutdown_handler.shutdown().unwrap();
494+
495+
let output = output.lock().unwrap();
496+
let output = std::str::from_utf8(&output).unwrap();
497+
let output = remap_timestamps_in_console_output(output);
498+
499+
assert_snapshot!(output, @r"
500+
1970-01-01T00:00:00.000000Z INFO logfire::internal::exporters::console::tests root span
501+
1970-01-01T00:00:00.000001Z INFO logfire::internal::exporters::console::tests hello world span
502+
1970-01-01T00:00:00.000002Z INFO logfire::internal::exporters::console::tests hello world log
503+
1970-01-01T00:00:00.000003Z ERROR logfire panic: oh no! location=src/internal/exporters/console.rs:488:17, backtrace=disabled backtrace
446504
");
447505
}
448506
}

0 commit comments

Comments
 (0)