如何实现附加到文件的记录器?

时间:2015-05-13 00:21:54

标签: logging rust

我尝试实施log::Log,以便对log()的调用将消息附加到文件中。这是我的记录器:

pub struct MyLogger {
    loglevel: LogLevelFilter,
    logfile: Option<File>,
}

执行log :: Log:

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.loglevel
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}\t| {}\t| {}", record.level(), record.target(), record.args());
            self.logfile.write_all(msg.as_bytes()).unwrap();
        }
    }
}

这是可以理解的,因为log()没有采用可变引用,因此失败了。我不能采用可变参考,因为那样我就不能正确地实现这种类型,那么实现这一目标的惯用方法是什么?

1 个答案:

答案 0 :(得分:3)

每当您需要提供不可变的界面但在幕后进行变异时,您可以使用内部可变性。这样做的常见方法是std::cell。文档调出了这个特定的用例:

  

因为你必须使用变异来实现最初被定义为采取&amp; self的特征方法。

具体来说,在这种情况下我会尝试使用RefCell

不幸的是,Log要求实施者也是Sync + Send,但细胞不是。这意味着我们需要升级到可以处理多个线程的东西。那个东西是Mutex

extern crate log;

use std::fs::File;
use std::io::Write;
use std::sync::Mutex;
use log::{LogLevelFilter,LogMetadata,LogRecord,Log};

pub struct FileLogger {
    loglevel: LogLevelFilter,
    logfile: Option<Mutex<File>>,
}

impl Log for FileLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.loglevel
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}\t| {}\t| {}", record.level(), record.target(), record.args());
            self.logfile.as_ref().map(|f| {
                f.lock().unwrap().write_all(msg.as_bytes()).unwrap()
            });
        }
    }
}

#[test]
fn it_works() {
}