GithubHelp home page GithubHelp logo

emabee / flexi_logger Goto Github PK

View Code? Open in Web Editor NEW
277.0 277.0 44.0 2.03 MB

A flexible logger for rust programs that can write to stderr, stdout, and/or to log files

License: Apache License 2.0

Rust 100.00%

flexi_logger's People

Contributors

asib avatar atul9 avatar avl avatar azoyan avatar bheylin avatar bsilver8192 avatar cgramza avatar complexspaces avatar dallenng avatar devzbysiu avatar emabee avatar flofriday avatar henquist avatar ijackson avatar jacobtread avatar jesdazrez avatar jnicholls avatar mbodmer avatar mgeisler avatar mpalmer avatar osa1 avatar petreeftime avatar pieterpalmers avatar rlee287 avatar slckl avatar vmx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flexi_logger's Issues

Support For Multiple Log Files

Does FlexiLogger support multiple log files? Not sure if I see a clear way todo it from the examples.

The use case is I have an application that hosts a basic web api and services out a few assets using actix-web. The application also does a lot of background processing.

I want the web request logs to go into their own file vs the application logs. However everything is hosted in one process.

Thanks!

LogSpecification: env() and parse() should return Result

It's a bit of a pain that these just silently fall back to some default log spec. If I start a long-running process (months long), I want it to die immediately if no log spec was found (or it failed to parse the spec). At the moment, this just prints a message, which could easily be missed. Now when I come back in a couple of months, my logs are all out of whack, because I didn't see the message.

If you'd be willing to allow it, may I submit a PR to change these methods to return a Result, so that:

  • if env() doesn't find a RUST_LOG environment variable, it returns an Err
  • if parse() fails to parse the spec, it returns an Err

Alternatively, to maintain backwards compatibility, I could add new methods e.g. env_result() or something like that.

Specfile not correctly interpreted?

When initializing flexi_logger with an initial logspec like "info", and configuring it to use an already existing specfile that uses more trace levels (e.g. including "debug" and "trace2), then the additional trace levels do not become effective (in the example only "error", "warn" and "info" will be printed.

[feature request] Criterion::AgeOrSize

One feature that could get added is Criterion::AgeOrSize(age, u64) where log rotation would happen when either the file has become older than the specified age, or it has exceeded the size specified in bytes.

Add format for stdout

Follow-up on #47 .

Currently, one can write this:

.log_target(LogTarget::File)
.duplicate_to_stderr(Duplicate::All)
.duplicate_to_stdout(Duplicate::Info)

However, stderr and stdout use the same format. If stderr is pointing to a file, this means that either stdout will be colorless, or that your file will contain colors.

A good thing to do would be to allow users to specify two different formats for stdout and stderr.

See [this comment] :)

Formatting performance

Hi,

I noticed that formatting the message with format! before logging is much faster than letting the logger do it. I would expect the performance to be similar or the logger to be slightly faster. Is this an expected behavior?

info!("{}", s);                // 1700-2600us
info!("{}", format!("{}", s)); // 200-700us

Here is a simple test program:

[dependencies]
log = "0.4.6"
flexi_logger = "0.11.1"
use std::fmt;
use std::time::Instant;

struct Struct {
    data: [u8; 32],
}

impl fmt::Display for Struct {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.data)
    }
}

fn main() {
    let _log_handle = flexi_logger::Logger::with_str("info")
        .start()
        .unwrap();

    let mut structs = Vec::new();
    for i in 0..10 {
        structs.push(Struct { data: [i as u8; 32] });
    }

    {   // With format
        let start = Instant::now();
        for s in &structs {
            log::info!("{}", format!("{}", s));
        }
        eprintln!("with format: {:?}", start.elapsed()); // 2-7ms
    }

    {   // Plain logger
        let start = Instant::now();
        for s in &structs {
            log::info!("{}", s);
        }
        eprintln!("plain: {:?}", start.elapsed()); // 17-26ms
    }
}

The length of the message does not matter that much, it's more about how many segments the Display implementation writes. Is there maybe some buffering problem?

I can reproduce on Windows 10 with PowerShell and on Ubuntu Server.

How to log to stdout and to file?

fn main() {
    let exe_path = format!("{}", std::env::current_exe().unwrap().parent().unwrap().display());

    let criterion = flexi_logger::Criterion::Age(flexi_logger::Age::Day);

    flexi_logger::Logger::with_env_or_str("info")
        .log_target(LogTarget::StdOut)
        .log_to_file()
        .directory(exe_path)
        .format(flexi_logger::detailed_format)
        .print_message()
        .rotate(criterion, flexi_logger::Naming::Timestamps, flexi_logger::Cleanup::Never)
        .start()
        .unwrap();

    info!("Started application!");
}

Only logs to the file for me. How do I log to both CLI and a file?

flexi_logger Performance

I switch from slog_async to flexi_logger and lost ~20% throughput. The log level is set to info and less than 10 lines are logged per second. Any reason for this performance drop?

I suspect few things but please help me here.

  1. For slog, I used features to remove debug statements at compile time:
slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_info"] }

but this is not supported by flexi_logger. I did use log level features as below.

log = { version = "0.4.11", features = ["max_level_trace", "release_max_level_info"] }

  1. slog uses async sink with channel size as ~64K but don't see similar config for flexi_logger. Any way to use async / buffer logging using flexi_logger?

Missing log records at the end

Not a bug report but an end-user question:

Sometimes my program or my test seems to have ended already before all has been logged. The symptom is that sometimes the last few logging records are missing.

What should I do? Somehow get the logging thread then wait for it to end?

I tried thread::yield_now(), thread::sleep(), io::stderr().lock().flush(), etc., but sometimes records are still missing. Often an additional strategic dummy info!() somewhere helps.

rotating based on time

Is it possible to rotate logs based on time rather than size? (ex. rotate daily instead of rotating once it reaches a certain size). This is a pretty common logging practice and I only see size in the docs.

0.7.0 creates an empty log file

Since I upgraded from 0.6.14 to 0.7.0, I'm getting a file created although I only want logging to stdout. The file is however empty. It's named like this:

wong_2018-03-06_19-09-44.log

I've double checked, and downgrading to 0.6.14 works, the file is not created anymore.

This is my init:

    let log_level = match matches.occurrences_of("verbosity") {
        0 => flexi_logger::Level::Info,
        1 => flexi_logger::Level::Debug,
        _ => flexi_logger::Level::Trace,
    };

    let log_spec = flexi_logger::LogSpecBuilder::new()
        .default(flexi_logger::Level::Info.to_level_filter())
        .module("wong", log_level.to_level_filter())
        .build();

    flexi_logger::Logger::with(log_spec)
        .format(log_format)
        .start()
        .unwrap();

Get filters from different sources?

Hi, and thank you for this amazing crate.
I'm currently trying to add module filters coming from different sources. I'd like for my program to have some preset module filters, then check if there are more filters defined with RUST_LOG, and then ultimately add some features passed in by an argument.

The code would look like:

fn setup_logger(filter: &str) {
  let mut builder = LogSpecBuilder::new();
  // Set my preset module filters
  builder.module("myfirstmodule", LevelFilter::Trace);
  builder.module("mysecondmodule", LevelFilter::Info);
  builder.default(LevelFilter::Error);

  // See if RUST_LOG defines any module filters
  builder.add_env();

  // Add the filter passed in as parameter
  build.add_str(filter);
  
  // Create the LogSpec
  let spec = builder.build();
  
  // Start the logger
  Logger::with(spec).start().unwrap();
}

However I see the builder has no method like add_env() or add_str(), and LogSpecification and Logger only provide associated functions to do that, not methods.

Am I doing it wrong? Or would it be a nice feature to add some methods that allow gettings filters from env / str in the builder?

Compressed logs should unambiguously be gzip files ending in .gz, not "zip" files

Hi. Thanks for your contribution to the Rust ecosystem.

I was reading the documentation for the compressed logging. I was puzzled to find all this discussion of "zip" files. It would be highly unusual for a program to write logs in actual zip format (the format expected by unzip). Traditional log management programs like logrotate and savelog make gzip files ending in .gz. Tools like zgrep which are usually used for inspecting logs expect gzip files.

I looked at the code, and indeed flexi_logger does make gzipped logfiles. But it calls them .zip, and the documentation is wrong too. Unfortunately I don't think this can fixed without at least some kind of breaking change: currently the file contents and file extension do not match.

I suggest that the right complete fix is to change (i) the file extension, from .zip to .gz (ii) the documentation, to refer to gzip rather than zip, (iii) all the in-Rust names, changing Zip to Gzip everywhere, (iv) all the corresponding names in the configuration (env, specfile, etc.). [Option 1]

How much do you want to worry about compatibility ? In some of these cases it would be possible to provide aliases, although that's a fair amount of work. I think we could provide aliases for the builder methods and probably for the configuration. [Option 2]

Going in the other direction, we could retain the existing programmatic names and merely change the docs and the file extension. That would avoid this being a build break, and in practice would be unlikely to break production systems, although it would leave the anomalous names in Rust source code and logger spec files. This is also quite easy, since the spec handling wouldn't need changing :-). [Option 3]

Since we'll be changing the file extension, I guess we should arrange to at least rotate away the .zip files made by older versions of flexi_logger, to avoid a situation where ancient .zip files , obsoleted by recent .gz files, are retained forever.

Please let me know what you prefer. I am happy to do the work to implement what I call options 1 and 3 above. My recommendation would be to do option 3 right away and then think about whether you need to go on to option 1 or 2.

I apologise for filing what you may see as a duplicate of #42. But I felt #42's framing was wrong. I wanted to set out a coherent (but opinionated) summary of the situation as I see it, under a corresponding title. I hope you find this helpful.

Add compatibility with multi_log

Please add compatibility with multi_log:
https://docs.rs/multi_log/0.1.2/multi_log

That would allow me to use flexi_logger with winlog (Windows Event Logger).

Right now start() calls log::set_boxed_logger() itself. It would be great if there was a function that returned the set_boxed_logger() parameter instead of calling the function, so that the users could call set_boxed_logger() themselves, allowing multi_log to work.

Documentation for flexi_logger::Logger::rotate_over_size

The documentation states:

By default, the log file will grow indefinitely. With this option, when the log file reaches or exceeds the specified file size, the file will be closed and a new file will be opened. Also the filename pattern changes - instead of the timestamp, a serial number is included into the filename.

But after calling flexi_logger::Logger::rotate_over_size(), I get a filename with a timestamp and a serial number. This is with v0.9.0.

Rotate seems not removing old log files

Seems it does not remove old log files after restart.

     Logger::with_env_or_str("debug")
        .log_to_file()
        .format(opt_format)
        .rotate(
            Criterion::Age(Age::Day),
            Naming::Timestamps,
            Cleanup::KeepLogFiles(6),
        )

Logger::format alters ::with_env_or_str parametrization behaviour.

Hi,

I'm a little at loss on why this might be...

This works perfectly fine:

Logger::with_env_or_str("mymod1=info, mymod2=error") 
    .start()
    .unwrap_or_else(|e| panic!("Logger initialization failed with {}", e));

Expected and get; mymod1 logs at level info and mymod2 at level error unless I override the string default with the RUST_LOG="info, ..." which in turn also does work perfectly as expected.

However:

Logger::with_env_or_str("mymod1=info, mymod2=error")
    .format(opt_format)
    .start()
    .unwrap_or_else(|e| panic!("Logger initialization failed with {}", e));

Expected same as above but with changed formatting (tried with detailed_format and opt_format).

What I get instead is no output at all. Unless I specify "info, mymod1=info, mymod2=error" in which case I get the intended behaviour parsed from the string (everything: info, mymod1: info, mymod2: error). Also works if I specify via RUST_LOG. But on not passing the leading "info, " string does not get parsed as expected.

Any ideas why this might be happening?

Best regards,
lwk

Add Additional Primary Writer

I might be missing something but it seems like the add_writer requires calling all the logging macros with a target. I can't see any way to add an additional writer that always get's used.

Would adding some way to add writers that always get logged to be accepted?

My use case is I want to write a custom writer for the windows event viewer but also use the file log writer to keep text logs for my application.

Thanks!

strange character escapes

The output in stdout looks fine, but the output that is written to files seems to have some weird character escapes: ^[[1;38;5;196mERROR^[[0m [babblebot::web] ^[[1;38;5;196mmissing field 'access_token' at line 1 column 74^[[0m. Any idea why this might be happening?

Remaining call to print_err

Revision 5b741cb replaced print_err with eprintln, but there is one remaining call to print_err in flexi_writer.rs on line 204 (only visible when compiling on linux).

Feature request: option to print to **both** a file and stderr

Title says it all :) I can use tail -f, but it'd be nice if I needn't too. There's functionality for duplicated logs to stdout, but that won't work for my use-case, because stdout needs to be valid JSON.

Oh, and thanks for writing the library, it's really awesome!

Unable to customize format to not contain timestamp

Hi,

I've been turning this one around from one side to another and seem not to be able to get it right...

The objective was to customize formatting such as to get the with_thread formatting version minus the timestamp being logged to stderr. This because it is being logged through systemd (by capture of stdout/stderr), which already keeps track of the date and time, prepending it already... so if I go for the build-in with_thread formatter, the timestamp ends up being printed twice in each line.

My attempt; (copy&paste with_thread and modify...)

pub fn formatter(w: &mut Write, record: &LogRecord) -> Result<(), IoError>
{
    write!(
        w,
        "T[{:?}] {} [{}:{}] {}",
        thread::current().name().unwrap_or("<unnamed>"),
        record.level(),
        record.file().unwrap_or("<unnamed>"),
        record.line().unwrap_or(0),
        &record.args()
    )
}

...and the venerable main...

fn main()
{
    Logger::with_env_or_str("info")
        .format(formatter)
        .start()
        .unwrap_or_else(|e| panic!("Logger initialization failed with {}", e));
}

But to no avail. What am I doing wrong?
Any help would be much appreciated.

Best regards,
lwk

Zipfile error

Hello,

When I try to unzip file using Linux (Ubuntu) unzip app get:

Archive: core_r00000.log.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.

I seems that the logger is making corrupt zip files.

Note that module names with dashes must use underscores in log level filter option

Warning: new to writing real Rust, might mess up terminology… 🐻 with me

When binary crate has a dash in its name, e.g. in Cargo.toml:

[package]
name = "thing-doer"
version = "0.1.0"

the appropriate filter string is not:

LogOptions::new()
        .init(Some("thing-doer=trace"))
        .unwrap_or_else(|e|{ panic!("Logger initialization failed with {}", e)} );

but rather:

LogOptions::new()
        .init(Some("thing_doer=trace"))
        .unwrap_or_else(|e|{ panic!("Logger initialization failed with {}", e)} );

I discovered this the hard way, by logging not working upon setup and then creating my own log format to output the record.target(). The output of record.target() was thing_doer and not thing-doer.

I think this might be a "problem" in the log crate but this should probably be documented in flexi_logger since it uses that target for comparing the named log level configurations.

I'm setting my log config like this:

    let log_level_config = format!("{name}={level}", name = crate_name!().to_string().replace("-", "_"), level = "trace");

    LogOptions::new()
        //…
        .init(Some(log_level_config))
        .unwrap_or_else(|e|{ panic!("Logger initialization failed with {}", e)} );

I've worked around it by using that replace() method so I don't have to think about it for now. I may regret that.

Create a log file only when needed instead of on initialization?

Currently when using a file target flexi_logger creates the log file on initialization. My app doesn't print a lot of logs by default so that means an empty file is created for every run. Would it be possible to at least add an option to create the file only when needed? (i.e. the first time a log line is printed)

Pin minimum supported rust version in .travis.yml

It's hard to know what minimum supported rust version is used for this crate! This means that I'm not sure what rust version to bump to - at the moment I'm getting the following build failure when building against Rust 1.42:

error: attributes are not yet allowed on `if` expressions
##[error]   --> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/flexi_logger-0.15.11/src/logger.rs:163:9
    |
163 |         #[cfg(feature = "colors")]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^

It would be really useful for folks downstream if an explicit version was pinned in the .travis.yml - at the moment it's only tested against stable, beta, and nightly.

Rotating log file names

Hello again!

Was wondering if you're open to changing the way this crate rotates log files?

It'd be nicer if the logs were always written to the same file, e.g. logs/my_proj.log, and once that file reaches the size limit, the file is renamed to logs/my_proj_r00001.log, and then the program recreates logs/my_proj.log and continues to write there. That way, if you want to follow the logs, you don't need to re-enter the follow command every time the file rotates.

Question: Support for custom file name without infix

My application uses slog and would like to replace with flexi_logger so log-rotation can be supported without using external utility.

  1. Is it possible to configure the log file name which is not same as process name?
  2. How can I define log-file name without _rCURRENT? In my current implementation, log files are rotated (using Logrotate linux util) as kdb.log, kdb-1.log, kdb-2.log
  3. Does flexi_logger writes to file async using buffer?

Some text is invisible with colored terminal output

Hi

First, thanks for this great logger!

I'm using Terminator terminal on Linux with solarized dark theme. Whenever I choose any of the colored output some of the text is invisible or close to the background color. Is there a way to provide my own color choices?

Zipping old files blocks all logging for a while

Hey!
Thanks for writing this library and making it available!

I've run into a problem. I run a project on a raspberry pi, which has a bunch of threads that e.g. poll some attached hardware for changes. For debugging, I log the raw values they get, among other things. All my logs are written to files and everything above warnings is copied to stderr.
The problem is this: I set up log rotation, keeping 5 plain-text files and 30 zipped ones. They fill up quite quickly with debug logging on, but that's not surprising. Now, whenever the logs are rotated and an old one is zipped, nothing can log anymore for as long as that takes.

Let me illustrate with a bunch of logs :) This is a fresh start, with no log files, so five plain text files are produced (this doesn't take long), and then later one file is zipped (this takes a while):

Log is written to logs/raspitest_rCURRENT.log
Server is listening on: http://[::1]:3000
[2020-01-29 14:05:40.745225 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 2918µs behind
[2020-01-29 14:05:40.752097 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 1558µs behind
[2020-01-29 14:05:40.760958 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 3750µs behind
[2020-01-29 14:05:40.777664 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 1387µs behind
[2020-01-29 14:05:40.792007 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 2462µs behind
[2020-01-29 14:05:40.894974 +00:00] WARN [raspitest::dht22] src\dht22.rs:96: unable to read from pin 26: Checksum
Log is written to logs/raspitest_rCURRENT.log
[2020-01-29 14:05:41.895071 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 101µs behind
[2020-01-29 14:05:42.988239 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 7554µs behind
[2020-01-29 14:05:44.185762 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 406µs behind
[2020-01-29 14:05:44.421706 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 1663µs behind
Log is written to logs/raspitest_rCURRENT.log
[2020-01-29 14:05:47.943784 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 215µs behind
Log is written to logs/raspitest_rCURRENT.log
[2020-01-29 14:05:49.726632 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 259µs behind
[2020-01-29 14:05:49.740501 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 22µs behind
[2020-01-29 14:05:49.756751 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 1068µs behind
[2020-01-29 14:05:50.273502 +00:00] WARN [raspitest::mcp23017_input] src\mcp23017_input.rs:131: took too long, lagging 4147µs behind
[2020-01-29 14:05:50.274273 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 2994µs behind
Log is written to logs/raspitest_rCURRENT.log
[2020-01-29 14:05:52.989480 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 1677µs behind
[2020-01-29 14:05:55.467321 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 294µs behind
Log is written to logs/raspitest_rCURRENT.log
[2020-01-29 14:05:57.984365 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 4783µs behind
Log is written to logs/raspitest_rCURRENT.log
[2020-01-29 14:06:04.791070 +00:00] WARN [raspitest::mcp23017_input] src\mcp23017_input.rs:131: took too long, lagging 4856814µs behind
[2020-01-29 14:06:04.792825 +00:00] WARN [raspitest::pca9685_sync] src\pca9685_sync.rs:87: took too long, lagging 4864683µs behind

I run these things pretty close to their limit, so they're always lagging a bit behind. But note how, after the last rotation, they lag behind a lot. I suspect this is because they tried to debug-log something, but got blocked.

Do you think I got the problem about right?

The obvious solution for me, for now, is to not debug-log (at least in production 😄 ). Long-term: Can we maybe move the zipping to another thread?

Best,

Crash in specfile-watcher

Hi!

First of all, let me express my thanks for creating the excellent flexi_logger crate!

I noticed a crash in logger.rs, line 661:

thread 'flexi_logger-specfile-watcher' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/flexi_logger-0.15.2/src/logger.rs:661:40

I'm using flexi_logger 0.15.2 .

The problem occurred when I removed some log files which were present in the same directory that the specfile was located in.

The problem seems to be this line:

if path.canonicalize().unwrap() == specfile {

Apparently the path that is to be canonicalized must actually exist, or the line above will panic.

Add tests for rotation

Prepare empty /non-empty log files etc before logger is initialized and verify correct behavior afterwards.

Colored output?

Hi,

it would be nice to be able to opt-in colored output.

If you need suggestions, ping me!

Use CRLF on Windows

On Windows textfiles commonly end in a carriage return + line feed ("\r\n"). flexi_logger's FileLogWriter only uses the simple line feed ("\n") common to Unix systems. I am using this crate for logging of a Windows service. An administrator may want to inspect log files using Notepad, as they cannot rely on more sophisticated tools to be present.

I am starting to work on this as it should not be too complex to add.

Make primary writers public?

I'm trying to log things to a file, stderr, and stdout at the same time.

To do that I must create a new writer for Stdout which I've done this way:

struct StdoutWriter {
    format: FormatFunction,
    log_level: log::LevelFilter
}

impl StdoutWriter {
    fn new(format: FormatFunction, log_level: LevelFilter) -> Self {
        StdoutWriter { format, log_level}
    }
}

impl LogWriter for StdoutWriter {
    #[inline]
    fn write(&self, now: &mut DeferredNow, record: &Record) -> std::io::Result<()> {
        (self.format)(&mut std::io::stdout(), now, record)
    }

    fn flush(&self) -> std::io::Result<()> {
        std::io::stdout().flush()
    }

    fn max_log_level(&self) -> log::LevelFilter {
        self.log_level
    }
}

However, I was wondering if flexi_logger couldn't expose the StdoutWriter that it already uses internally (as a Primary Writer), to make that easier.
Or maybe I'm missing something :)

Thanks!

proposal: implement Drop for LoggerHandle

When I want to use buffer, I must keep the LoggerHandle which returned by start and then call shutdown myself, like this:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let logger = Logger::with_str("info")
       .log_target(LogTarget::File)
       .buffer_and_flush()
       .start()?;
    // ... do all your work ...
    logger.shutdown();
    Ok(())
}

I think it's very unrust to do this, and implement a drop method for LoggerHandle make it more rust, the main function will envolved to like this:

fn main() -> Result<(), Box<dyn std::error::Error>> {
   let _logger_guard = Logger::with_str("info")
      .log_target(LogTarget::File)
      .buffer_and_flush()
      .start()?;
   // ... do all your work ...
   Ok(())
}

Detect terminal color support

Hi,

Right now if I run a flexi_logger-enabled application from terminal (on Linux) I get a properly colored output.
However, if I launch it from another application (without terminal) and capture its output to show it in GUI, I still get color escape sequences in the text, and the displayed text is garbled in the GUI.

I think flexi_logger should use ::atty::is(::atty::Stream::Stdout) or similar to check whether colored output is actually supported.

Thanks!

Crashed with core dump after press Ctrl + C

When quit the application by std::process::exit(0),flexi_logger will be crashed with core dump as bellow.

[2019-08-21 07:07:38.330857 +08:00] INFO [ns_nice/src/web_server.rs:87] Start web server.
^Cthread '' panicked at 'cannot access stderr during shutdown', src/libcore/option.rs:1034:5
stack backtrace:
0: 0x55878d11bc8b - backtrace::backtrace::libunwind::trace::hfe5db90796807973
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.29/src/backtrace/libunwind.rs:88
1: 0x55878d11bc8b - backtrace::backtrace::trace_unsynchronized::h34b865a835594335
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.29/src/backtrace/mod.rs:66
2: 0x55878d11bc8b - std::sys_common::backtrace::_print::h527254ae44989167
at src/libstd/sys_common/backtrace.rs:47
3: 0x55878d11bc8b - std::sys_common::backtrace::print::he85dd5ddddf46503
at src/libstd/sys_common/backtrace.rs:36
4: 0x55878d11bc8b - std::panicking::default_hook::{{closure}}::h847a2eb38b396f14
at src/libstd/panicking.rs:200
5: 0x55878d11b967 - std::panicking::default_hook::h2ca0f9a30a0e206b
at src/libstd/panicking.rs:214
6: 0x55878d11c400 - std::panicking::rust_panic_with_hook::hffcefc09751839d1
at src/libstd/panicking.rs:477
7: 0x55878d11bf82 - std::panicking::continue_panic_fmt::hc0f142c930c846fc
at src/libstd/panicking.rs:384
8: 0x55878d11be66 - rust_begin_unwind
at src/libstd/panicking.rs:311
9: 0x55878d13961d - core::panicking::panic_fmt::h2daf88b2616ca2b2
at src/libcore/panicking.rs:85
10: 0x55878d139687 - core::option::expect_failed::h4b77ebe6e62ec3a1
at src/libcore/option.rs:1034
11: 0x55878d111fe5 - core::option::Option::expect::h5a6ae296007c8783
at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b/src/libcore/option.rs:314
12: 0x55878d111fe5 - std::io::stdio::stderr::h4547669837e9df0d
at src/libstd/io/stdio.rs:629
13: 0x55878ce5293a - flexi_logger::primary_writer::StdErrWriter::write::h4c538220bc2b5d9a
at /home/gary/.cargo/registry/src/github.com-1ecc6299db9ec823/flexi_logger-0.14.1/src/primary_writer.rs:82
14: 0x55878ce52778 - flexi_logger::primary_writer::PrimaryWriter::write::haa0c9f6ce84cc295
at /home/gary/.cargo/registry/src/github.com-1ecc6299db9ec823/flexi_logger-0.14.1/src/primary_writer.rs:47

Log files blank after restart

I seem to be running into a strange issue. When I first start up my program, with an empty logs folder, it creates babblebot_rCURRENT.log and logs to the file. If I stop my program, and start it again, I now see babblebot_r00000.log and babblebot_rCURRENT.log in my logs folder, but both are completely blank and no new output is appended. I still see log output in stdout.

[FEATURE] Targetting specific targets?

I was using env_logger and doing something like this:

let mut builder = env_logger::Builder::new();
builder.parse_filters("my-target=trace");
builder.try_init().unwrap();
trace!(target: "my-target", "this gets logged!");

As you can see, I setting a specific loglevel for a specific target. Quite handy for debugging!
I've been trying a way to do that with flexi_logger, but I haven't managed to succeed.

let spec = LogSpecification::parse("my-target=trace").unwrap();
Logger::with(spec).start().unwrap();
trace!(target: "my-target", "this doesn't get logged!");

As you can see there are two problems:

  1. LogSpecification::parse("my-target=trace").unwrap() will panic because hyphens are not allowed (but they are allowed as target by log)
  2. Even by having my_target=trace and trace!(target: "my_target", ...), nothing gets logged.

I think there's a way around using a new writer as described in the docs.
However this solution is cumbersome: imagine the use case where you want users to pass different targets via a CLI interface (--log 'my_target=trace, my_other_target=info).

I'm not sure however whether or not this feature could get easily implemented in flexi_logger. :)

No colored output (with default settings and "colors" feature activated)

Hi,

Thanks for creating 'flexi_logger'!

For some reason, I don't get any colored output with the default settings (or any other settings I tried).

When I run cargo run --example colors, however, I get colored output (the output of Cargo is colored, as well).

Do you have any idea what the problem could be?

I'm using flexi_logger = "0.15.12" in Cargo.toml (so the "colors" feature is activated), and besides the defaults I have tested the following:

    let logger_config = "warn, main=trace, devtools_protocol_client=trace";
    flexi_logger::Logger::with_str(logger_config)
        .check_parser_error()
        .expect("Logger config string formatted incorrectly")
        .log_target(flexi_logger::LogTarget::StdOut)
        .format_for_stdout(flexi_logger::colored_detailed_format)
        .format_for_stderr(flexi_logger::colored_detailed_format)
        .start()
        .expect("Failed to start logger");

It would be nice if it somehow would be possible to activate colored output, because 'flexi_logger' looks really nice :)

start_with_specfile doesn't allow multiple instances of the program

Hi,

My program uses flexi_logger with a specfile. But, if I launch 2 instances in parallel, the second one does not enable logging and fails with: "Filesystem notifications for the specfile could not be set up".

I think it should be possible to run 2 instances with the same configuration without specfile filesystem notifications. Perhaps add an option to disable the "automatic reloading at runtime" feature?

Thanks!

Old log files are not removed if rCURRENT doesn't overflow

When a FileLogWriterState is created, it sometimes rotate_output_file_to_date but does not call remove_or_zip_too_old_logfiles. The latter is only called when an existing _rCURRENT overflows. Therefore when a downstream program is run repeatedly, but doesn't generate enough log messages to trigger mount_next_linewriter_if_necessary in a single run, old rCURRENT messages can accumulate indefinitely in the log directory.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.