errors: Maintain caller location in to_log (#1994)

* utils/errors: Add caller location to `to_log`

by building the log record manually and filling in the callers file and
line manually. It is currently not possible to determine a callers
module, hence the module is now set to "???" in all log entries logged
this way. Nonetheless, the file and line number are sufficient to find
the logs source.

* utils/errors: Reimplement `to_log`

default implementation in the `LoggableError` trait.

* changelog: Add PR #1994

errors: Maintain caller location in `to_log`
This commit is contained in:
har7an 2022-12-07 07:51:23 +00:00 committed by GitHub
parent fd7a5398cd
commit 81287a276f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 7 deletions

View File

@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* fix(themes): missing tokyo-night-dark theme (https://github.com/zellij-org/zellij/pull/1972)
* refactor(plugins): fix plugin loading data flow (https://github.com/zellij-org/zellij/pull/1995)
* refactor(messaging): reduce extraneous cross-thread messaging (https://github.com/zellij-org/zellij/pull/1996)
* errors: preserve caller location in `to_log` (https://github.com/zellij-org/zellij/pull/1994)
## [0.33.0] - 2022-11-10

View File

@ -96,15 +96,33 @@ pub trait LoggableError<T>: Sized {
#[track_caller]
fn print_error<F: Fn(&str)>(self, fun: F) -> Self;
/// Convenienve function, calls `print_error` with the closure `|msg| log::error!("{}", msg)`.
// Dev note:
// Currently this hides the location of the caller, because it will show this very line as
// "source" of the logging call. This isn't correct, because it may have been called by other
// functions, too. To track this, we need to attach `#[track_caller]` to the closure below,
// which isn't stabilized yet: https://github.com/rust-lang/rust/issues/87417
/// Convenienve function, calls `print_error` and logs the result as error.
///
/// This is not a wrapper around `log::error!`, because the `log` crate uses a lot of compile
/// time macros from `std` to determine caller locations/module names etc. Since these are
/// resolved at compile time in the location they are written, they would always resolve to the
/// location in this function where `log::error!` is called, masking the real caller location.
/// Hence, we build the log message ourselves. This means that we lose the information about
/// the calling module (Because it can only be resolved at compile time), however the callers
/// file and line number are preserved.
#[track_caller]
fn to_log(self) -> Self {
self.print_error(|msg| log::error!("{}", msg))
let caller = std::panic::Location::caller();
self.print_error(|msg| {
// Build the log entry manually
// NOTE: The log entry has no module path associated with it. This is because `log`
// gets the module path from the `std::module_path!()` macro, which is replaced at
// compile time in the location it is written!
log::logger().log(
&log::Record::builder()
.level(log::Level::Error)
.args(format_args!("{}", msg))
.file(Some(caller.file()))
.line(Some(caller.line()))
.module_path(None)
.build(),
);
})
}
/// Convenienve function, calls `print_error` with the closure `|msg| eprintln!("{}", msg)`.