Ten kod wykrywa zdarzenia śledzenia:

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(...)");
});

Chcę, aby pierwsze globalne linie statyczne były zainicjowane i przechowywane w thread_local!(), dzięki czemu jest zainicjowany tylko raz na każdy wątek.

Wtedy powinienem być w stanie użyć tej instancji specyficznej dla wątku Dispatch do zasięgu abonentów zdarzeń. Powyższy kod jest pobierany z funkcji i let instrukcje. Jako zmienne statyczne, jedna ich nie działa i mieli tak samo problem w thread_local!().

pub static (non_blocking, _guard:WorkerGuard):(NonBlocking:WorkerGuard) = tracing_appender::non_blocking(file_appender);

Błąd jak poniżej

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

Drugim problemem był zrozumienie, w jaki sposób są inicjowane w lokalnym modzie nici.

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"}
1
Sarvi Shanmugham 28 lipiec 2020, 20:57

1 odpowiedź

Najlepsza odpowiedź

Owiń deklaracje static za pomocą makro thread_local!, możesz uzyskać dostęp do każdej wartości za pomocą metody {x2}}, co zwróci wartość unikalną dla wątku.

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();
}

Upewniłem się, że także przechowywać WorkerGuard w lokalnym miejscu, aby nie wychodzi z zakresu po zainicjowaniu MY_DISPATCH. Dzieje się tak dlatego, że dokumentacja dla tracing_appender::non_blocking Stany:

Ta funkcja zwraca krotkę NonBlocking i WorkerGuard. NonBlocking implementuje MakeWriter, który integruje się z tracing_subscriber. WorkerGuard jest osłoną spadkową, która jest odpowiedzialna za spłukiwanie pozostałych dzienników, gdy program kończy się.

Należy pamiętać, że WorkerGuard zwracany przez non_blocking musi być przypisany do wiązania, który nie jest _, jak _ spowoduje to {{x4 }} Natychmiast spadł. Niezamierzone krople WorkerGuard Usuń gwarancję, że dzienniki zostaną przepłukane podczas zakończenia programu, w panikę lub w inny sposób.

W ten sposób strażnik zostanie upuszczony podczas wyjścia wątku. Należy jednak pamiętać, że wbudowana pamięć wbudowanej wątku Rdza ma dziwne dziwactwo o inicjalizacji i zniszczenia. Zobacz dokumentację dla {x0}}. Szczególnie:

W systemach UNIX, gdy używany jest TLS oparty na PTHREAD, destruktory nie będą uruchamiane dla wartości TLS na głównym wątku, gdy wyjdzie. Należy pamiętać, że aplikacja wyjdzie natychmiast po zysku głównym nitki.

Dlatego na głównym wątku należy zadzwonić bezpośrednio make_dispatch(), a nie MY_DISPATCH, dzięki czemu zostanie upuszczony, gdy program wyjścił (ale zauważ, że ogólnie rzecz biorąc, nie są upuszczane, zwłaszcza w trakcie Panica lub std::process::exit itp.; Dlatego nadal istnieje szansa, że niektóre dzienniki można utracić, podobnie jak natura większości nie blokujących I / O).

1
Coder-256 28 lipiec 2020, 23:14