-
Couldn't load subscription status.
- Fork 118
ffi: allow to change tracing level and callback more than once #1111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
ffi: allow to change tracing level and callback more than once #1111
Conversation
4a69e1f to
ba6df41
Compare
|
hi @kssenii just checking on this PR - it's still marked as draft, do you need reviews, etc.? |
|
@zachschuermann, hi, no, I will undraft when ready for review. |
7e72421 to
fdc0610
Compare
8bd28ca to
af406cb
Compare
f7b8814 to
8ac86aa
Compare
8ac86aa to
007e76c
Compare
ffi/src/ffi_tracing.rs
Outdated
| match set_global_default(dispatch.clone()) { | ||
| Ok(()) => { | ||
| *locked_state = Some(GlobalTracingState { | ||
| dispatch, | ||
| reload_handle, | ||
| event_callback: Some(event_callback), | ||
| log_line_callback: None, | ||
| }); | ||
| Ok(()) | ||
| } | ||
| Err(e) => Err(Error::generic(format!( | ||
| "Unable to set default subscriber: {e}" | ||
| ))), | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| match set_global_default(dispatch.clone()) { | |
| Ok(()) => { | |
| *locked_state = Some(GlobalTracingState { | |
| dispatch, | |
| reload_handle, | |
| event_callback: Some(event_callback), | |
| log_line_callback: None, | |
| }); | |
| Ok(()) | |
| } | |
| Err(e) => Err(Error::generic(format!( | |
| "Unable to set default subscriber: {e}" | |
| ))), | |
| } | |
| set_global_default(dispatch.clone()).map_err(|e| Error::generic(format!( | |
| "Unable to set default subscriber: {e}" | |
| ))?; | |
| *locked_state = Some(GlobalTracingState { | |
| dispatch, | |
| reload_handle, | |
| event_callback: Some(event_callback), | |
| log_line_callback: None, | |
| }); | |
| Ok(()) |
ffi/src/ffi_tracing.rs
Outdated
| static TRACING_STATE: LazyLock<Mutex<Option<GlobalTracingState>>> = | ||
| LazyLock::new(|| Mutex::new(None)); | ||
|
|
||
| fn get_event_dispatcher( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this is creating a new one rather than getting an existing one.
| fn get_event_dispatcher( | |
| fn create_event_dispatcher( |
ffi/src/ffi_tracing.rs
Outdated
| if let Some(state) = locked_state.as_mut() { | ||
| if let Some(event_callback) = &state.event_callback { | ||
| *event_callback.lock().unwrap() = callback; | ||
| } else { | ||
| state.event_callback = Some(Arc::new(Mutex::new(callback))); | ||
| } | ||
| return state | ||
| .reload_handle | ||
| .reload(LevelFilter::from(max_level)) | ||
| .map_err(|e| { | ||
| warn!("Failed to reload tracing level: {e}"); | ||
| Error::generic(format!("Unable to reload subscriber: {e}")) | ||
| }); | ||
| } else { | ||
| let (dispatch, reload_handle, event_callback) = get_event_dispatcher(callback, max_level); | ||
| match set_global_default(dispatch.clone()) { | ||
| Ok(()) => { | ||
| *locked_state = Some(GlobalTracingState { | ||
| dispatch, | ||
| reload_handle, | ||
| event_callback: Some(event_callback), | ||
| log_line_callback: None, | ||
| }); | ||
| Ok(()) | ||
| } | ||
| Err(e) => Err(Error::generic(format!( | ||
| "Unable to set default subscriber: {e}" | ||
| ))), | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're duplicating the logic to do the following in both setup_event_subscriber and setup_log_line_subscriber:
- Get state
- If it hasn't been initialized, then initialized it using
get_.*_dispatcher. Update state. - If it has been initialized, set callback, perform a reload.
We're also manipulating GlobalTracingState a bunch here. I'd propose to:
- Make this functionality part of GlobalTracingState.
GlobalTracingState.register_new_callback(event_callback, max_level) - I'd prefer if possible to make GlobalTracingState internally handle the
Option. ie:
static TRACING_STATE: LazyLock<Mutex<GlobalTracingState>> =
LazyLock::new(|| Mutex::new(GlobalTracingState::uninitiaziled()));
This way, all the tracing handling is done in GlobalTracingState, and we can track where the global state is being modified.
ffi/src/ffi_tracing.rs
Outdated
| let ok = expected_log_lines.is_empty() | ||
| || expected_log_lines.iter().any(|expected_log_line| { | ||
| let res = line_str.ends_with(expected_log_line); | ||
| //println!("Line: {line_str}, expected: {expected_log_line}, res: {res}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| //println!("Line: {line_str}, expected: {expected_log_line}, res: {res}"); |
|
|
||
| // ensure we can setup again with a new callback and a new tracing level | ||
| unsafe { | ||
| enable_event_tracing(event_callback_2, Level::DEBUG); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do the following?
enable_event_tracing()
enable_log_line_tracing()
From what I gather, this isn't possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, not possible (or at least I did not manage to make it work though I tried), I also added related comment here
delta-kernel-rs/ffi/src/ffi_tracing.rs
Lines 810 to 812 in 00aab70
| #[test] | |
| #[ignore] // We cannot run this test if test_enable_log_line_tracing was run before - see comment there, however this test works if run individually. | |
| fn test_enable_event_tracing() { |
3ccd287 to
00aab70
Compare
00aab70 to
9e7b4f0
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1111 +/- ##
==========================================
- Coverage 84.86% 84.64% -0.22%
==========================================
Files 119 119
Lines 30880 31075 +195
Branches 30880 31075 +195
==========================================
+ Hits 26206 26304 +98
- Misses 3395 3485 +90
- Partials 1279 1286 +7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks! took an initial pass and had a few comments. will look more deeply in the next day or so
ffi/src/ffi_tracing.rs
Outdated
| use tracing::warn; | ||
| use tracing::trace; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
| use tracing::warn; | |
| use tracing::trace; | |
| use tracing::{trace, warn}; |
ffi/src/ffi_tracing.rs
Outdated
| file: kernel_string_slice!(file), | ||
| }; | ||
| (self.callback)(event); | ||
| let cb = self.callback.lock().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not call unwrap as it panics and can crash the engine. This is a gross situation because we can't really inform the engine that something went wrong :) Maybe we can just error! log in that case and hope that something else on the rust side is logging.
ffi/src/ffi_tracing.rs
Outdated
| } | ||
|
|
||
| if let (Some(reload), Some(event_cb)) = (&self.reload_handle, &self.event_callback) { | ||
| *event_cb.lock().unwrap() = callback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto on unwrap here
ffi/src/ffi_tracing.rs
Outdated
| let message = String::from_utf8_lossy(&buf); | ||
| let message = kernel_string_slice!(message); | ||
| (self.callback)(message); | ||
| let cb = self.callback.lock().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unwrap
ffi/src/ffi_tracing.rs
Outdated
| let message = "INTERNAL KERNEL ERROR: Could not lock message buffer."; | ||
| let message = kernel_string_slice!(message); | ||
| (self.callback)(message); | ||
| let cb = self.callback.lock().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unwrap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting close!
ffi/src/ffi_tracing.rs
Outdated
| if let Some(ref msgs) = *lock { | ||
| assert_eq!(msgs.len(), expected_lines.len()); | ||
| for (got, expect) in msgs.iter().zip(expected_lines) { | ||
| println!("Got: {got}"); | ||
| assert!(got.ends_with(expect)); | ||
| assert!(got.contains(expected_level_str)); | ||
| assert!(got.contains("delta_kernel_ffi::ffi_tracing::tests")); | ||
| if let Some(ref tstr) = expected_time_str { | ||
| assert!(got.contains(tstr)); | ||
| } | ||
| } | ||
| } else { | ||
| panic!("Messages wasn't Some"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if let Some(ref msgs) = *lock { | |
| assert_eq!(msgs.len(), expected_lines.len()); | |
| for (got, expect) in msgs.iter().zip(expected_lines) { | |
| println!("Got: {got}"); | |
| assert!(got.ends_with(expect)); | |
| assert!(got.contains(expected_level_str)); | |
| assert!(got.contains("delta_kernel_ffi::ffi_tracing::tests")); | |
| if let Some(ref tstr) = expected_time_str { | |
| assert!(got.contains(tstr)); | |
| } | |
| } | |
| } else { | |
| panic!("Messages wasn't Some"); | |
| } | |
| let Some(ref msgs) = *lock else { | |
| panic!("Messages wasn't Some"); | |
| } | |
| assert_eq!(msgs.len(), expected_lines.len()); | |
| for (got, expect) in msgs.iter().zip(expected_lines) { | |
| println!("Got: {got}"); | |
| assert!(got.ends_with(expect)); | |
| assert!(got.contains(expected_level_str)); | |
| assert!(got.contains("delta_kernel_ffi::ffi_tracing::tests")); | |
| if let Some(ref tstr) = expected_time_str { | |
| assert!(got.contains(tstr)); | |
| } | |
| } |
ffi/src/ffi_tracing.rs
Outdated
| } | ||
| let dispatch = get_event_dispatcher(callback, max_level); | ||
| set_global_default(dispatch) | ||
| let mut state = TRACING_STATE.lock().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| let mut state = TRACING_STATE.lock().unwrap(); | |
| let mut state = TRACING_STATE.lock().map_err(|e| Error::generic("Poisoned mutex while setting up event subscriber"); |
ffi/src/ffi_tracing.rs
Outdated
| return Err(Error::generic("max_level out of range")); | ||
| } | ||
| let dispatch = get_log_line_dispatch( | ||
| let mut state = TRACING_STATE.lock().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| let mut state = TRACING_STATE.lock().unwrap(); | |
| let mut state = TRACING_STATE.lock().map_err(|e| Error::generic("Poisoned mutex while setting up log_line_subscriber")?; |
ffi/src/ffi_tracing.rs
Outdated
| if let Ok(mut event_cb) = event_cb.lock() { | ||
| *event_cb = callback; | ||
| } else { | ||
| error!("Failed to acquire lock for event callback (mutex poisoned)."); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let the caller know something went wrong
| if let Ok(mut event_cb) = event_cb.lock() { | |
| *event_cb = callback; | |
| } else { | |
| error!("Failed to acquire lock for event callback (mutex poisoned)."); | |
| } | |
| let (mut event_cb) = event_cb.lock().map_err(|e| Error::generic("Failed to acquire lock for event callback (mutex poisoned).")?; | |
| *event_cb = callback; |
ffi/src/ffi_tracing.rs
Outdated
| if let Ok(mut log_cb) = log_cb.lock() { | ||
| *log_cb = callback; | ||
| } else { | ||
| error!("Failed to acquire lock for log callback (mutex poisoned)."); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if let Ok(mut log_cb) = log_cb.lock() { | |
| *log_cb = callback; | |
| } else { | |
| error!("Failed to acquire lock for log callback (mutex poisoned)."); | |
| } | |
| let mut log_cb = log_cb.lock().map_err(|e| Error::generic("Failed to acquire lock for log callback (mutex poisoned)."))?; | |
| *log_cb = callback; |
What changes are proposed in this pull request?
#1109
How was this change tested?
Added a new test
change_event_tracking_level.