rust-cli / env_logger Goto Github PK
View Code? Open in Web Editor NEWA logging implementation for `log` which is configured via an environment variable.
Home Page: https://docs.rs/env_logger
License: Apache License 2.0
A logging implementation for `log` which is configured via an environment variable.
Home Page: https://docs.rs/env_logger
License: Apache License 2.0
I read through #87 and I can't help but (humbly) second-guess (no pun intended) the decision. In my opinion, second-level precision is too coarse, and nanosecond-level is too fine, and milliseconds are the happy medium. And I would argue that it doesn't even need to be configurable. I'd propose that if default_format_timestamp
logged millisecond-level timestamps, that would be good enough for almost everybody. I realize humantime
doesn't support milliseconds, so I guess this would mean going back to chronos, unless we can convince humantime to add that...
As soon as you enable RUST_LOG
, even for just a small module that logs infrequently, the performance of your program is going to go drastically downhill.
Example: https://i.imgur.com/al4BJUn.png
+ 94.04% 0.39% rust-bitcoin-in rust-bitcoin-indexer [.] <serde_json::read::IoRead<R> as serde_json::read::Read<
+ 93.61% 0.48% rust-bitcoin-in rust-bitcoin-indexer [.] serde_json::read::next_or_eof
+ 93.19% 0.60% rust-bitcoin-in rust-bitcoin-indexer [.] std::io::read_one_byte
+ 92.55% 0.14% rust-bitcoin-in rust-bitcoin-indexer [.] std::io::impls::<impl std::io::Read for &'a mut R>::rea
+ 92.43% 1.50% rust-bitcoin-in rust-bitcoin-indexer [.] <hyper::client::response::Response as std::io::Read>::r
+ 91.04% 0.27% rust-bitcoin-in rust-bitcoin-indexer [.] <hyper::http::h1::Http11Message as std::io::Read>::read
+ 90.72% 2.96% rust-bitcoin-in rust-bitcoin-indexer [.] <hyper::http::h1::HttpReader<R> as std::io::Read>::read
- 86.85% 82.85% rust-bitcoin-in rust-bitcoin-indexer [.] log::__log
- 80.92% <serde_json::read::IoRead<R> as serde_json::read::Read<'de>>::parse_str
+ serde_json::read::next_or_eof
+ 4.00% log::__log
+ 1.91% jsonrpc::client::Client::send_request
+ 2.44% 0.02% rust-bitcoin-in rust-bitcoin-indexer [.] rust_bitcoin_indexer::db::parse_node_block
+ 2.20% 0.00% rust-bitcoin-in rust-bitcoin-indexer [.] jsonrpc::client::Client::send_request
+ 2.18% 0.00% rust-bitcoin-in rust-bitcoin-indexer [.] serde::de::impls::<impl serde::de::Deserialize<'de> for
+ 2.18% 0.00% rust-bitcoin-in rust-bitcoin-indexer [.] <&'a mut serde_json::de::Deserializer<R> as serde::de::
+ 2.17% 0.00% rust-bitcoin-in rust-bitcoin-indexer [.] serde_json::de::from_reader
+ 2.01% 1.91% rust-bitcoin-in rust-bitcoin-indexer [.] log::logger
+ 1.71% 0.43% rust-bitcoin-in rust-bitcoin-indexer [.] <env_logger::Logger as log::Log>::log
+ 1.59% 0.13% rust-bitcoin-in rust-bitcoin-indexer [.] core::fmt::write
+ 1.44% 1.21% rust-bitcoin-in rust-bitcoin-indexer [.] bitcoin::util::misc::he
As you can see, just because serde_json::read::Read
has some trace!
in parse_str
somewhere, is completely destroying my program, for which I've enabled debugging just for my main module.
Is there anything that can be done about it?
Our current env_logger
format is pretty good, but I think there are a few tweaks we can make to it that would improve readability, parsability and compactness. Before that though, I think it would be good if we thought about whether or not we consider the default format as part of our semver'd API.
I think we should be mindful, but not against changing the default format in patches. We do eventually want it to be fairly stable, but if a user needs a truly stable format then they should use a custom format.
I'm keen to hear what other people think about this!
I think we can make some tweaks to our current format that should be an improvement for the majority of users:
Trace => TRC
Debug => DBG
Info => INF
Warn => WRN
Error => ERR
To see how this might look, here's a few examples using our current format, and the changes I was thinking about:
This is also a bit subjective, so I'd like to know what you all think about the current and proposed format too!
Gray colors are useful for the less-than-essential details. But it looks like this uses termcolor, so maybe I should open an issue on BurntSushi/ripgrep instead?
May be it is not so clear title, but
On Windows with default formatter, colors are enabled. When running some app with env_logger
inside console, it outputs colored messaged.
So it does (tries to do) when you redirect your app to a file (via app.exe 2> app.log
) and that file becomes pretty messy (full of lines like �[m�[32m INFO�[m 2018-01-17T14:56:26Z
).
I think it would be worth to detect whether STDERR is a tty (console in terms of Windows) or a file.
I am not sure whether it is an issue of env_logger
or termcolor
, but ripgrep
, for instance, behaves correctly. So may be it can be done here.
As per log
's review, formatting currently requires allocation via creating a String
. This should be avoided.
Hello,
log = "0.3.8"
env_logger = "0.4.3"
Is it free to use macro debug! or trace! when LogLevelFilter is set to Info? LogLevelFilter::Info
Is There extra overhead when using LogLevelFilter::Info or LogLevelFilter::Debug and using trace!(very_large_stream)? is it not called or is redirected to /dev/null? how it done? is it in runtime or at compile time?
`
let mut builder = LogBuilder::new();
if matches.is_present("debug") {
let format = |record: &LogRecord| {
format!(
"{} [{}] {}:{} {:?} - {}",
Local::now().format("%d-%m-%Y %H:%M:%S"),
record.level(),
record.location().file(),
record.location().line(),
thread::current().id(),
record.args()
)
};
if matches.is_present("trace") {
builder.format(format).filter(None, LogLevelFilter::Trace);
} else {
builder.format(format).filter(None, LogLevelFilter::Debug);
}
} else {
let format = |record: &LogRecord| {
format!(
"{} [{}] - {}",
Local::now().format("%d-%m-%Y %H:%M:%S"),
record.level(),
record.args()
)
};
builder.format(format).filter(None, LogLevelFilter::Info);
}
builder.init().unwrap();
`
env_logger
already got some care during the log
review. Lets do an additional pass to conform with the API guidelines as a separate crate.
as_
, to_
, into_
conventions ([C-CONV])iter
, iter_mut
, into_iter
([C-ITER])_mut
and _ref
([C-OWN-SUFFIX])Copy
, Clone
, Eq
, PartialEq
, Ord
, PartialOrd
, Hash
, Debug
,Display
, Default
From
, AsRef
, AsMut
([C-CONV-TRAITS])FromIterator
and Extend
([C-COLLECT])Serialize
, Deserialize
([C-SERDE])"serde"
cfg option that enables Serde ([C-SERDE-CFG])Send
and Sync
where possible ([C-SEND-SYNC])Send
and Sync
([C-SEND-SYNC-ERR])()
([C-MEANINGFUL-ERR])Hex
, Octal
, Binary
formatting ([C-NUM-FMT])?
, not try!
, not unwrap
([C-QUESTION-MARK])Deref
and DerefMut
([C-DEREF])Deref
and DerefMut
never fail ([C-DEREF-FAIL])bool
or Option
([C-CUSTOM-TYPE])bitflags
, not enums ([C-BITFLAG])Debug
([C-DEBUG])Debug
representation is never empty ([C-DEBUG-NONEMPTY])Originally raised in #103
Currently, I don't see a nice way to change logging levels dynamically. (Or is there?). It is not very friendly with log::set_max_level_filter either to able to make even small changes.
Would be nice to be able to make small changes if not full reparse during runtime. It becomes extremely helpful in server environments to be able to to that.
I often write projects in Python where my logging level should be warn
or even info
if the user doesn't specify anything.
Currently, the docs are unclear whether there's a way to set a logging level, but still allow it to be overridden by RUST_LOG
, other than by checking for the RUST_LOG
environment variable and setting it if it's absent before calling env_logger::init()
... a solution which, I think you'll agree, looks like an ugly hack.
Hi there!
While it is possible to define a custom formatting via the Builder
, often one only wants to adjust small things. For example, the timestamp is way too noisy for my application, so I want to disable it. But now I have to do everything else by myself. Especially right now I cannot use colors, so I cannot implement the formatting I want. It would be nice to say something like builder.with_timestamps(false)
. Sure, this would introduce one (or a few, if we want to add options for other parts -- like the module path -- as well) boolean flag that has to be checked for each log message. But that should be fine, right?
We've got a couple of open questions related to the logging sink:
stdout
, stderr
and null)stderr
when there are multiple threads/processes involved (#19 (comment))It would be good to iterate towards a design that satisfies all these things, without complicating things too much. I think it might be worth looking at opening up the Target
enum into a trait, and seeing where that gets us.
stderr
There's a private API for writing colours that we use in the default format. This should be public so anyone building their own format can use it. Colours currently use an enum from termcolor
, which means we'd need to make it a public dependency, or wrap it somehow.
Target
is missing the following traits:
Clone
Copy
Eq
PartialEq
Ord
PartialOrd
Hash
would it be reasonable to add wasm support via stdweb?
Hello,
I'm changing println! to info! when using the env_logger and trying to change target to stdout. However it does not seem to make any different. All logs still go to console. Is not it supposed to be different?
Cargo.toml:
[dependencies]
log = "0.4"
env_logger = "0.5"
lib.rs:
extern crate log;
extern crate env_logger;.
logger.rs
extern crate log;
extern crate env_logger;
use std::env;
use log::*;
use self::env_logger::{Builder, Target};
::std::env::set_var("RUST_LOG", "info");
println!("env RUST_LOG as {:?}", env::var("RUST_LOG"));
let mut builder = Builder::new();
builder.target(Target::Stdout);
if env::var("RUST_LOG").is_ok() {
builder.parse(&env::var("RUST_LOG").unwrap());
}
builder.init();
info!("builder={:?}", builder);
Note that I did get following error and not sure why So I made change as instructed by adding "self", it passed.
8 | use env_logger::{Builder, Target};
| ^^^^^^^^^^ Did you mean self::env_logger
?
==========================
Here is the output of cargo run as well as docker run:
env RUST_LOG as Ok("info")
INFO 2018-11-02T19:17:37Z: myapp::utils::logger: builder=Logger { filter: Filter { filter: None, directives: [] }, writer: Logger { target: Stdout, write_style: Auto } }
We should include an ISO-formatted timestamp on the default log format. It's not uncommon for apps running in virtualised or headless environments to capture stdout/stderr for later review, and having timestamps is a helpful bit of insight.
Since formats are configurable, tools like cargo that are probably being watched can opt-out of displaying a timestamp to reduce noise.
Builder::try_init
and the root try_init
functionBuilder::init
and the root init
functionIn my application I really need to see the exact time it takes in milliseconds between each log. This will give me an idea if something is slow.
As suggested here, I'm asking if it would be possible to implement a toggle to have it more precise?
I can't seem to get cargo test to properly capture either STDOUT or STDERR when logging with env_logger. My understanding is that cargo should capture both when tests pass and only show the results when tests fail.
Instead, all logs from env_logger/log macros are interleaved as the tests are running, and none are displayed in the "--- test_name stdout ----" section.
Here's the code I'm using:
extern crate env_logger;
#[test]
fn test_name() -> Result<(), Box<Error>> {
env_logger::init();
println!("PRINTLN"); // gets captured properly
// none of these are captured
error!("error");
info!("info");
trace!("trace");
Err(Box::from("test"))
}
I don't have the same issue using another crate such as simple_logger:
#[test]
fn test_name() -> Result<(), Box<Error>> {
simple_logger::init().unwrap();
println!("PRINTLN");
error!("error");
info!("info");
trace!("trace");
Err(Box::from("test"))
}
Some environments, e.g. Kubernetes, already timestamp every log message. Thus, adding our own timestamp if wastefully duplicative. We currently have a custom formatter to disable the timestamping.
That works OK, as far as the runtime characteristic of the application are concerned. However, because Cargo downloads each dependency serially, and because Cargo builds each dependency serially, every single dependency inhibits the build performance by some constant factor that's independent of the complexity of the dependency. Some applications have continuous integration and/or container build systems that have to rebuild everything from scratch any time any dependency changes, and/or on every commit, so minimizing the from-scratch download + build time is important.
I noticed when upgrading such an application from env_logger 0.4 to env_logger 0.5 that chrono and then later humantime were added as dependencies. In our situation this is a regression, since it increases the number of dependencies (and thus the application size and the build time) compared to env_logger 0.4. We can't stay with env_logger 0.4 because some other libraries we use depend on env_logger 0.5 already; we're actually trying to optimize the build so that only only version of env_logger (0.5) needs to be built.
For these reasons, it would be beneficial to make the dependency on humantime, and the default timestamping functionality in general, optional, e.g. by making them configurable via a default feature, perhaps named "timestamp".
On Linux at least, logging to stderr redirected to a file by the shell, logs emitted by multiple threads can race so that one thread's message is printed between another thread's message and its newline. I guess the newline is printed with a separate syscall, but it shouldn't be.
edit: sorry, pressed Enter too fast.
I've had an issue where our library (Spidermonkey) has two ways to initialize the global logger:
In the program case, the program will first initialize its logger with a specific LevelFilter; then the code runs into our initialization path that runs env_logger::try_init()
which fails since a logger has already been set. Unfortunately, this also resets the LevelFilter. There's an easy workaround on our side, but I thought in general you wouldn't want to implicitly override the LevelFilter if there was already a logger set. Thoughts?
Program received signal SIGSEGV, Segmentation fault.
0x0020ca34 in env_logger::Format::into_boxed_fn::_$u7b$$u7b$closure$u7d$$u7d$::ha67fa042fe85d5e5 ()
(gdb) bt
#0 0x0020ca34 in env_logger::Format::into_boxed_fn::_$u7b$$u7b$closure$u7d$$u7d$::ha67fa042fe85d5e5 ()
#1 0x0020b6d8 in _$LT$env_logger..Logger$u20$as$u20$log..Log$GT$::log::h9c942721ccf6110b ()
#2 0x002f9068 in carrier::main::h4eed1b21f4e13567 ()
#3 0x00304248 in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h931ab8c3620c5b29 ()
#4 0x002f8d68 in main ()
Any way to log to a file?
If not could it be a feature request?
Tracking a few issues for env_logger
that are still filed in log
.
It'd be nice if tags were created for each released version, to make the specific commits easier to find.
I think it would be useful if env_logger
had an option to include thread name.
E. g. RUST_LOG=myapp=debug?thread_name=true myapp
Would help debug multithreaded apps.
From https://public.etherpad-mozilla.org/p/rust-api-guidelines-env_logger.
impl
s for Target
Logger
Logger::new
and Logger::filter
unwrap
from exampleslog
be hyperlinksCargo.toml
with readme
and new linksfilter_module
and filter_level
as separate functions to Builder
?Debug
for Logger
and Filter
Some environments will never, or will practically never, output to a terminal, or otherwise do not ever need or want stylized output. This is often the case for an application that is intended to be deployed in a containerized environment like Kubernetes or Docker, for example.
Because Cargo downloads each dependency serially, and because Cargo builds each dependency serially, every single dependency inhibits the build performance by some constant factor that's independent of the complexity of the dependency. Further, some applications have continuous integration and/or container build systems that have to rebuild everything from scratch any time any dependency changes, and/or on every commit.
I noticed when upgrading such an application from env_logger 0.4 to env_logger 0.5 that termcolor
and atty
were added as dependencies. In our situation this is a regression, since it increases the number of dependencies (and thus the application size and the build time) compared to env_logger 0.4. We can't stay with env_logger 0.4 because some other libraries we use depend on env_logger 0.5 already; we're actually trying to optimize the build so that only only version of env_logger (0.5) needs to be built.
For these reasons, it would be beneficial to make the dependencies on termcolor and atty optional, controlled by a default feature, perhaps named "style" or "tty", so that we can use default-features = false
to disable them. Or, otherwise, provide a way to get the configurability by environment variables that env_logger provides, without these dependencies.
Hello!
This is more of a question, but it seems the default loglevel for env_logger includes error
. While I would like to allow setting a log level with RUST_LOG=
, I would also like to fully disable logging if that environment variable isn't set because it's interfering with the process indicator. I have my own error handling and one of my dependencies is using error!
in some cases which messes with the terminal.
I was wondering: What's the most elegant way to have an env_logger that defaults to "fully silent"? :)
Logger
doesn't currently have any impls. We should define which ones are needed and implement them.
I have code that implements the log::Log traits to send my log to a remote syslog. Can I set env_logger to forward everything to it?
Over time, I've grown accustomed to a CHANGELOG file. It's cool if you want to use GitHub releases, but it's not immediately obvious that this is where the notes are. A plain text file with a link would be sufficient.
Hi all!
The 0.5.x
release of env_logger
has been around for a while now, and I've started thinking it's about time to think about 0.6.x
. I'd like to find out whether there's anything anyone would like changed while we've got the opportunity.
There are two changes I'd like to work into the new release that really just lay down a policy around logically breaking changes to the default format going forward:
log
like structured logging would need additions to the format and requiring a breaking bump for these sorts of additions will limit discoverability).It's a bit of a fresh start with a (hopefully) clear policy around the format that lets us keep improving env_logger
through its format while we're still 0.x
. Post stabilization would be a new conversation.
Does anyone have any other thoughts on that? Or any other breaking improvements to the API they'd like to see?
Was raised in #33 that the current timestamp format is pretty verbose, but could be simpler while still being useful and valid RFC3339. We should:
+00:00
with a simple Z
Without this it's impossible to get colored output on Windows.
Make sure multiple calls to Write::write
in log formats don't result in logs being interleaved when accessed concurrently.
Not sure if this is the correct place for this, and excuse me if this information is already in the docs 😅
How does this crate behave when stdout
is broken? The std::print
macro's panic when they can't write to stdout
. I would hope this is not the case in this crate.
I had a look through the source code but I'm unable to find it.
I really like the new format, including the color!
Unfortunately when the log output is piped and stored elsewhere (for example in AWS CloudWatch) I see all the control characters which makes reading the log actually harder.
Could the color be disabled with a feature flag?
I noticed this a couple of times now: I'm considering using log and env_logger for my logging, but env_logger would require that I set RUST_LOG every time I want to actually have output, or I wouldn't get anything at all. What I want to do would be something along these lines:
env_logger::init_or("something=info");
So, if $RUST_LOG
is not set, env_logger would use something=info
instead. This could be overwritten with RUST_LOG= ./app
, causing env_logger to use an empty string.
As per log
's review. Check out pretty_env_logger
.
Issue in log
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.