-
Notifications
You must be signed in to change notification settings - Fork 250
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
Add basic features to CursiveLogger #719
Conversation
cursive-core/src/logger.rs
Outdated
pub fn init(self) { | ||
reserve_logs(self.log_size); | ||
log::set_logger(Box::leak(Box::new(self))).unwrap(); | ||
log::set_max_level(log::LevelFilter::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.
We could set the maximum of (int, ext) levels to avoid logging trace if it wouldn't be seen anyway.
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.
Done.
cursive-core/src/logger.rs
Outdated
/// Installs the logger with log. Calling twice will panic. | ||
pub fn init(self) { | ||
reserve_logs(self.log_size); | ||
log::set_logger(Box::leak(Box::new(self))).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 may want to use set_boxed_logger
, which hides the leaking away so it feels less dirty (even though it's really the same):
https://docs.rs/log/latest/log/fn.set_boxed_logger.html
I guess a "leak-free" version would keep CursiveLogger zero-sized and rely on a global/singleton state instead, but that may be more complex, with quite limited benefits (prevents leaks if init()
is called repeatedly).
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.
Yeah, I originally had used set_boxed_logger
but that's hidden behind the std
feature flag for log
and I didn't want to change the dependencies unless I had to.
As written, calling init()
multiple times panics anyways, so I don't think we have to worry about leaks. Having everything kept in global state might not be a bad idea since we shouldn't expect anyone to create multiple CursiveLogger
objects anyways.
I made another branch for this: cursivelogger_global. It is a bit more complicated and I don't know if I like the API ergonomics. One plus though is being able to change the log filter levels after initialization. I don't know if that's worth it.
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.
Why the Mutex<Cell<...>>
in that branch? Could a simple mutex work too? Or even RwLock
, might make the read-only case faster.
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.
I think I like this global branch! No feature change for the log dependency, uses lazy_static that we were already using...
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.
Yeah, both work, you're right. I don't know what I was thinking with Mutex<Cell<...>>
. Since LOGS
is a Mutex
anyway I'm not sure there's much of a speed difference.
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.
I created a PR for cursivelogger_global. There is a tiny issue with set_log_size
though.
cursive-core/src/logger.rs
Outdated
fn enabled(&self, _metadata: &log::Metadata) -> bool { | ||
true | ||
fn enabled(&self, metadata: &log::Metadata) -> bool { | ||
if metadata.target().contains("cursive_core") { |
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.
Maybe we should be more restrictive, requiring this to be a prefix of the target?
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.
Done.
Thanks for the work! Just a couple nitpicks. |
* Make CursiveLogger use globals * Avoid duplicate log queue reservations * Check log queue size on init, get rid of `LOG_SIZE`
@gyscos |
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.
Maybe we could use VecDeque::with_capacity
from lazy_static!
rather than manually calling reserve_logs
. It'd still only be called on the first use (so no wasted memory if users don't use this logger).
Not sure we even need to expose reserve_logs
? 🤷
What about the change to not having a set_log_size() function and just using reserve_logs()? (blaisdellma#1 (comment))
Yeah let's keep the API minimal, any power user should use a real serious solution.
cursive-core/src/logger.rs
Outdated
} | ||
|
||
/// Sets the internal log filter level. | ||
pub fn set_int_filter_level(level: log::LevelFilter) { |
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: could we call it set_internal_filter_level
, to prevent any ambiguity around int
?
Let's also extend set_external_filter_level
for consistency.
I don't care as much about the lazy static global as it's not public.
cursive-core/src/logger.rs
Outdated
/// If `RUST_LOG` is set, then both internal and external log levels are set to match. | ||
/// If `CURSIVE_LOG` is set, then the internal log level is set to match with precedence over | ||
/// `RUST_LOG`. | ||
pub fn set_filter_levels_with_env() { |
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
pub fn set_filter_levels_with_env() { | |
pub fn set_filter_levels_from_env() { |
cursive-core/src/logger.rs
Outdated
/// `RUST_LOG`. | ||
pub fn set_filter_levels_with_env() { | ||
if let Ok(rust_log) = std::env::var("RUST_LOG") { | ||
if let Ok(filter_level) = log::LevelFilter::from_str(&rust_log) { |
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.
I'd log (ha!) a warning in case we can't parse the level, rather than silently ignoring it.
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.
This is meant to be called before the logger is initialized, so any logged warning would be ignored. I guess you could call it after initialization, but then when initializing the log::set_max_level()
would be based on the default filter levels (which is fine, cause it defaults to trace). I'll add it anyway.
I'm personally in favor of not making breaking changes to the API unless necessary. I don't know that it hurts to have it there, but it's your call. |
Thanks again for all the work and updates, and sorry for the trouble! |
Hello,
This is my attempt at following the first of my suggestions in #714 .
I tried to leave as much alone as I could so that there would be no breaking changes with as many useful features as possible. Anyone using the logger now shouldn't have to change anything and get the exact same behavior. There shouldn't be any breaking changes to the existing API, either in function signatures or behavior.
Logging would use two different filter levels, one each for logs generated internally by cursive and externally by whatever else. This solves the issue in #714 as the debug messages won't clog the log with all the redraws from scrolling (assuming the filter levels are set appropriately). These levels are set either directly or by the environment variables
RUST_LOG
andCURSIVE_LOG
. I also added the ability to change the log queue size too. I hope this meets option 2 in #467 as a "good enough" feature set.Two small examples:
The whole
Box::leak(Box::new(self))
thing is to avoid having to add thestd
feature flag tolog
and changeCargo.toml
. This is exactly howlog
handlesset_boxed_logger
internally.