Rust 在不同的环境中是否可能有不同的记录器?
用途:Rust 在不同的环境中是否可能有不同的记录器?,rust,Rust,用途: 已注册单个全局静态记录器(Send+Sync)实例 所有的信息,警告,等等。宏从所有线程发送到全局记录器 您可以使用set\u max\u level 是否有可能以某种方式解开这个问题,并在不同的上下文中使用不同的记录器,例如,针对不同的线程 以下是我想要实现的具体示例: 目标“A”、“B”和“C”是不同的日志记录目标,例如A的控制台、B的文件和C的网络日志端点。A/B/C是什么并不重要,只是它们彼此不同 #[macro_use] extern crate log; use std
- 已注册单个全局静态
(记录器
)实例Send+Sync
- 所有的
信息代码>,
警告代码>,等等。宏从所有线程发送到全局记录器
- 您可以使用
set\u max\u level
#[macro_use]
extern crate log;
use std::thread::spawn;
use log::{set_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record};
struct Logger {}
impl Log for Logger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= Level::Info
}
fn log(&self, record: &Record) {
println!("{}", record.args());
}
fn flush(&self) {}
}
static LOGGER: Logger = Logger {};
fn init() {
set_logger(&LOGGER).unwrap();
set_max_level(LevelFilter::Info);
}
fn foo() {
// Should always log to target 'B'
info!("B");
}
fn main() {
init();
// Should log to target 'A'
info!("A");
foo();
spawn(move || {
// It would be nice, to be able to also, say, use a different
// logging level here, e.g. only log error!() in this thread.
// should log to target 'C'
info!("C");
// should still log to target 'B'
foo();
}).join()
.unwrap();
}
#[宏使用]
外部板条箱日志;
使用std::thread::spawn;
使用日志:{set_logger,set_max_level,level,LevelFilter,log,Metadata,Record};
结构记录器{}
记录器的impl日志{
启用fn(&self,元数据:&metadata)->bool{
metadata.level()最大级别;文档似乎是错误的,因此通常您会有一个函数来包装set\u max\u level
和set\u logger
,但这只是一个简单的示例。因为,您可以使用线程本地存储来建立一个记录器堆栈。然后您可以始终在堆栈顶部登录记录器:
use std::cell::RefCell;
trait Logger {
fn log(&self, message: &str);
}
struct StderrLogger;
impl Logger for StderrLogger {
fn log(&self, message: &str) {
eprintln!("Logger: {}", message);
}
}
struct NetworkLogger;
impl Logger for NetworkLogger {
fn log(&self, message: &str) {
eprintln!("The cloud: {}", message);
}
}
thread_local! {
static LOGGER: RefCell<Vec<Box<Logger>>> = RefCell::new(vec![Box::new(StderrLogger)]);
}
fn push_context<L, F, R>(l: L, f: F) -> R
where
L: Logger + 'static,
F: FnOnce() -> R,
{
LOGGER.with(|logger| logger.borrow_mut().push(Box::new(l)));
let r = f();
LOGGER.with(|logger| logger.borrow_mut().pop());
r
}
macro_rules! log {
($msg:expr) => {
LOGGER.with(|logger| {
if let Some(logger) = logger.borrow().last() {
logger.log($msg)
}
})
}
}
fn main() {
log!("a");
push_context(NetworkLogger, || {
log!("b");
});
log!("c");
}
使用std::cell::RefCell;
特征记录器{
fn日志(&self,消息:&str);
}
struct stderlogger;
stderlogger的impl记录器{
fn日志(&self,消息:&str){
eprintln!(“记录器:{}”,消息);
}
}
结构网络记录器;
网络记录器的impl记录器{
fn日志(&self,消息:&str){
eprintln!(“云:{}”,消息);
}
}
本地线程{
静态记录器:RefCell=RefCell::new(vec![Box::new(StderrLogger)];
}
fn推送上下文(l:l,f:f)->R
哪里
L:记录器+'静态,
F:FnOnce()->R,
{
LOGGER.with(| LOGGER | LOGGER.borrow_mut().push(Box::new(l));
设r=f();
LOGGER.with(| LOGGER | LOGGER.borrow_mut().pop());
R
}
宏规则!日志{
($msg:expr)=>{
记录器。带(|记录器|{
如果让一些(记录器)=logger.borrow().last(){
logger.log($msg)
}
})
}
}
fn main(){
日志!(“a”);
推送上下文(网络记录器,| |{
日志!(“b”);
});
日志!(“c”);
}
您需要有向堆栈添加新记录器并将其删除的方法(push\u context
)
我没有花时间将其与原木板条箱真正集成,但我相信这应该是直接完成的。您必须实现原木板条箱需要的任何特性,才能完成此log
宏中的工作
不过,我的观点是:全球任何东西,包括日志记录者,都是一种代码味道。当你开始想要在一个简单的抽象上强加越来越多的细节时,尤其如此
这确实帮助我澄清了我的想法:
日志记录是一项功能
- 支持日志记录(错误和信息)为
应用程序用户界面的一部分。这些消息是
计划由支持人员以及系统人员跟踪
管理员和操作员,以诊断故障或监视
运行系统的进度
- 诊断日志记录(调试和跟踪)
是程序员的基础设施。这些消息不应该被转换
因为他们的目的是帮助程序员
了解他们正在开发的系统内部的情况
前者应该是系统域的一部分,而不应该是二等公民。使用对应用程序有意义的方法创建自定义特性,并使用依赖项注入来传递
后者是我发现的类似于日志板条箱的东西,适合于倾倒原始数据来诊断野外的问题。您可以实现并注册一个记录器
,它向每个线程记录器
(可能跟踪),并且(假设您控制线程)让每个线程注册自己的记录器
(它不必是记录器
特征;您可以定义自己的特征,而不需要发送+同步
)。环境记录器中没有不安全的代码:✓&q=safesafe&type=@BurntSushi5我从来没有说过有。我所说的就是日志()一些日志程序实现也是如此。使用单例程序强制使用某种不安全的代码,即使你将其包装在一个不安全的代码后面。这是一个糟糕的设计,完全是这样,但我现在真正感兴趣的是试图找到一种实用的方法来使用它。/耸耸肩“日志包和各种实现中都有一堆不安全的代码”---内部可变性并不是天生的坏设计,它可以通过使用标准库中的安全抽象以多种不同的方式实现。如果您扩展此问题来解释您认为的“上下文记录器”是什么,也可能会有所帮助。您能否展示一个代码示例,以近似您希望使用记录器编写的代码?