gpt4 book ai didi

rust - 如何使用线程本地存储进行作用域事件跟踪?

转载 作者:行者123 更新时间:2023-12-03 11:37:07 27 4
gpt4 key购买 nike

此代码的作用域是跟踪事件:

extern crate tracing_appender;
extern crate tracing_subscriber;
extern crate tracing;

use tracing::{Level, event, };
use tracing::dispatcher::{with_default, Dispatch};
use std::thread;
use tracing_appender::rolling::{RollingFileAppender};
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
use tracing_subscriber::fmt::SubscriberBuilder;

pub static file_appender:RollingFileAppender = tracing_appender::rolling::never("/ws/sarvi-sjc/", "prefix.log");
pub static (non_blocking, _guard:WorkerGuard):(NonBlocking:WorkerGuard) = tracing_appender::non_blocking(file_appender);
pub static subscriber:SubscriberBuilder = tracing_subscriber::FmtSubscriber::builder()
.with_max_level(Level::TRACE)
.with_writer(non_blocking)
.finish();
pub static my_dispatch = Dispatch::new(subscriber);

with_default(&my_dispatch, || {
event!(Level::INFO, "chmod(...)");
});
我希望将第一条全局静态行初始化并存储在 thread_local!()中,以便每个线程仅初始化一次。
然后,我应该能够使用该特定于线程的 Dispatch实例来范围化事件订阅者。上面的代码是从函数内部获取的,它们是 let语句。作为静态变量,它们之一不起作用,并且在 thread_local!()中也有相同的问题。
pub static (non_blocking, _guard:WorkerGuard):(NonBlocking:WorkerGuard) = tracing_appender::non_blocking(file_appender);
错误如下
error: expected identifier, found `(`
--> src/lib.rs:13:12
|
13 | pub static (non_blocking, _guard:WorkerGuard):(NonBlocking:WorkerGuard) = tracing_appender::non_blocking(file_appender);
| ^ expected identifier
第二个问题是了解如何以线程局部方式初始化它们。
env_logger = "*"
tracing-subscriber = {version = "0.2.9", features = ["chrono", "env-filter", "fmt"]}
test-env-log = {version = "0.2.2", features = ["trace"] }
tracing-appender = {version = "0.1.1"}

最佳答案

static宏包装thread_local!声明,然后可以使用with方法访问每个值,该方法将返回线程唯一的值。

use tracing::{
dispatcher::{with_default, Dispatch},
event, Level,
};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::FmtSubscriber;

fn make_dispatch() -> (Dispatch, WorkerGuard) {
let file_appender = tracing_appender::rolling::never("ws/sarvi-sjc/", "prefix.log");
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let subscriber = FmtSubscriber::builder()
.with_max_level(Level::TRACE)
.with_writer(non_blocking)
.finish();
(Dispatch::new(subscriber), guard)
}

thread_local!(static MY_DISPATCH: (Dispatch, WorkerGuard) = make_dispatch());

fn main() {
// Main thread:
let (my_dispatch, _guard) = make_dispatch();
with_default(&my_dispatch, || {
event!(Level::INFO, "main thread");
});

// Other thread:
std::thread::spawn(|| {
MY_DISPATCH.with(|(my_dispatch, _guard)| {
with_default(&my_dispatch, || {
event!(Level::INFO, "other thread");
});
});
})
.join()
.unwrap();
}
我也确保将 WorkerGuard也存储在线程本地存储中,以便在初始化 MY_DISPATCH之后它不会超出范围。这是因为 tracing_appender::non_blocking 的文档指出:

This function returns a tuple of NonBlocking and WorkerGuard. NonBlocking implements MakeWriter which integrates with tracing_subscriber. WorkerGuard is a drop guard that is responsible for flushing any remaining logs when the program terminates.

Note that the WorkerGuard returned by non_blocking must be assigned to a binding that is not _, as _ will result in the WorkerGuard being dropped immediately. Unintentional drops of WorkerGuard remove the guarantee that logs will be flushed during a program's termination, in a panic or otherwise.


这样,当线程退出时,防护将被删除。但是,请记住,Rust的内置线程本地存储对初始化和销毁​​有一些奇怪的怪癖。请参阅 std::thread::LocalKey 的文档。尤其:

On Unix systems when pthread-based TLS is being used, destructors will not be run for TLS values on the main thread when it exits. Note that the application will exit immediately after the main thread exits as well.


因此,在主线程上,您应该直接调用 make_dispatch()而不是 MY_DISPATCH,以便在程序退出时将其删除(但请注意,通常不能保证删除所有内容,尤其是在紧急情况或 std::process::exit等情况下;因此,仍然存在一些日志可能丢失的机会,这是大多数非阻塞I/O的本质。

关于rust - 如何使用线程本地存储进行作用域事件跟踪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63140125/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com