如何实现附加到文件的记录器?
How to implement a logger that appends to a file?
我正在尝试实现 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()
没有采用可变引用。我不能采用可变引用,因为那样我就无法正确实现类型,那么实现这一目标的惯用方法是什么?
每当你需要呈现一个不可变的界面但在幕后进行变异时,你可以使用内部可变性。这样做的常用方法是使用 std::cell
中的内容。文档指出了这个特定的用例:
because you must employ mutation to implement a trait method that was originally defined to take &self.
具体来说,我会尝试在这种情况下使用 RefCell
。
不幸的是,Log
requires the implementer to also be Sync + Send
, but cells are not. That means we need to upgrade to something that can handle multiple threads. That something is 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() {
}
我正在尝试实现 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()
没有采用可变引用。我不能采用可变引用,因为那样我就无法正确实现类型,那么实现这一目标的惯用方法是什么?
每当你需要呈现一个不可变的界面但在幕后进行变异时,你可以使用内部可变性。这样做的常用方法是使用 std::cell
中的内容。文档指出了这个特定的用例:
because you must employ mutation to implement a trait method that was originally defined to take &self.
具体来说,我会尝试在这种情况下使用 RefCell
。
不幸的是,Log
requires the implementer to also be Sync + Send
, but cells are not. That means we need to upgrade to something that can handle multiple threads. That something is 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() {
}