Compile error for implementing Logging format


#1

My apologizes for this seemingly simple question. I must be having a brain fault and cannot figure this out.

I am getting the following compile error on my closure in this function:

error[E0619]: the type of this value must be known in this context
  --> src/utils/logger.rs:37:22
   |
37 |             writeln!(buf, "{:>5}|{:<30}|{:>35}:{:<4}| {}", record.level(), record.target(), record.location().file(), record.location().line(), record.args())
   |                      ^^^

here’s the code:

use std::env;
use std::sync::{Once, ONCE_INIT};
use env_logger::Builder;
use log::{Record, Level, Metadata, Log, LevelFilter};

static LOGGER_INIT: Once = ONCE_INIT;

pub fn init_log() {
    LOGGER_INIT.call_once(|| {
        let format = |buf, record: &Record| {
        writeln!(buf, "{:>5}|{:<30}|{:>35?}:{:<4?}| {}", record.level(), record.target(), record.file(), record.line(), record.args())
        };
        let mut builder = Builder::new();
        builder.format(format).filter(None, LevelFilter::Off);

        if env::var("RUST_LOG").is_ok() {
            builder.parse(&env::var("RUST_LOG").unwrap());
        }

        builder.init();
    });
}

Thanks in advance
Matt


#2

Type checker needs to know the type of buf there, which I believe is &mut env_logger::fmt::Formatter. In addition, you need to use std::io::Write so the writeln! can call write_fmt on it. So make the closure

let format = |buf: &mut env_logger::fmt::Formatter, record: &Record| { ... };

Alternatively, put the closure inline with builder.format(...) and let type inference figure out buf there:

builder.format(|buf, record| ...) // buf and record will both be inferred

#3

I’m not understanding this part…

I tried this:

use std::io::Write;
.....
Write(buf, "{:>5}|{:<30}|{:>35?}:{:<4?}| {}", record.level(), record.target(), record.file(), record.line(), record.args())

but I get compile errors on Write.

Matt


#4

Make sure you have:

use std::io::Write; // or use std::io::prelude::*

in your file. This makes Write methods available to be called.


#5

Sorry still not clear to me:

use std::env;
use std::sync::{Once, ONCE_INIT};
use std::io::Write;
use std::io::prelude::*;

use env_logger::{Builder, fmt};
use log::{Record, Level, Metadata, Log, LevelFilter};

static LOGGER_INIT: Once = ONCE_INIT;

pub fn init_log() {
    LOGGER_INIT.call_once(|| {
        let format = |buf: &mut fmt::Formatter, record: &Record| {
            Write::write_fmt(buf, "{:>5}|{:<30}|{:>35?}:{:<4?}| {}", record.level(), record.target(), record.file(), record.line(), record.args())
        };
        let mut builder = Builder::new();
        builder.format(format).filter(None, LevelFilter::Off);

        if env::var("RUST_LOG").is_ok() {
            builder.parse(&env::var("RUST_LOG").unwrap());
        }

        builder.init();
    });
}

This doesn’t compile.

Matt


#6

Take a look at playground


#7

my apologize for all of that. not sure why I couldn’t see the problem. you’re help got me working.

Matt