| Crates.io | tracing-async2 |
| lib.rs | tracing-async2 |
| version | 0.2.10 |
| created_at | 2025-05-20 20:01:27.170718+00 |
| updated_at | 2025-05-26 13:58:01.242221+00 |
| description | Generic tracing layer library for working with tracing events including for async work. |
| homepage | https://github.com/macprog-guy/tracing-async2.git |
| repository | https://github.com/macprog-guy/tracing-async2.git |
| max_upload_size | |
| id | 1682179 |
| size | 71,244 |
This crate makes it easy to create your own custom tracing layers using a simple callback mechanism. One abvious use is to store tracing events into a database but you could just as well send them to a downstream service using gRPC or http. Or, for testing purposes, to accumulate them into a vector.
This crate provides a set of tracing layers that can be used to process
[tracing::Event]s using simple callbacks or even in an asynchronous
context. This is done using variations the [CallbackLayer].
tracing_layer_async_within macroThis macro simplifies some async scenarios where the provided callback was
not Sync or Send. Here is an example of how you could use this macro to
create a layer that saves tracing events into a database using tokio_postgres:
#[tracing_layer_async_within]
pub fn pg_tracing_layer(client: &PGClient, event: OwnedEvent) -> Result<(), tokio_postgres::Error> {
// Do what needs to be done!
}
The above code gets expanded into the code below:
pub fn pg_tracing_layer(client: PGClient, buffer_size: usize) -> CallbackLayer {
let (tx, mut rx) = mpsc::channel::<OwnedEvent>(buffer_size);
tokio::spawn(async move {
let client = Arc::new(client);
while let Some(event) = rx.recv().await {
if let Err(e) = save(&client, event).await {
eprintln!("{} error: {}", "pg_tracing_layer", e);
}
}
});
pub async fn save(client: &PGClient, event: OwnedEvent) -> Result<(), tokio_postgres::Error> {
// Do what needs to be done!
}
channel_layer(tx)
}
Of note are the following:
The PGClient was declared as a reference but the generated returned function requires it to be owned.
buffer_size is an additional parameter to the generated function.
callback_layerIf your needs are really simple, like accumulating traces in a vector.
Then you can use the [callback_layer]:
use tracing_async2::{callback_layer, OwnedEvent};
use tracing_subscriber::{EnvFilter, prelude::*};
use std::sync::{Arc, RwLock};
let log = Arc::new(RwLock::new(Vec::new()));
let cb_log = log.clone();
tracing_subscriber::registry()
.with(EnvFilter::new("tracing_async2=trace"))
.with(callback_layer(move |event| {
if let Ok(mut log) = cb_log.write() {
log.push(OwnedEvent::from(event));
}
}))
.init();
channel_layerIf you ever had the need to record traces in a database or do something
asynchronously with [tracing::Event], then you can use the
[channel_layer]:
use tracing_async2::channel_layer;
use tracing_subscriber::{EnvFilter, prelude::*};
use tokio::{sync::mpsc, runtime, task};
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.expect("could not start tokio runtime");
rt.block_on(async move {
let (tx, mut rx) = mpsc::channel(100);
tracing_subscriber::registry()
.with(EnvFilter::new("tracing_async2=trace"))
.with(channel_layer(tx)) // <--- use the channel
.init();
tokio::spawn(async move {
while let Some(event) = rx.recv().await {
// Do something with the event like saving it to the database.
}
});
});
async_layerIf you don't want to handle the channel yourself, then you might consider
the use of [async_layer] instead:
use tracing_async2::async_layer;
use tracing_subscriber::{EnvFilter, prelude::*};
use tokio::{sync::mpsc, runtime, task};
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.expect("could not start tokio runtime");
rt.block_on(async move {
tracing_subscriber::registry()
.with(EnvFilter::new("tracing_async2=trace"))
.with(async_layer(16, move |event| {
async move {
// Do something with the event like saving it to the database.
}
}))
.init();
});
License: MIT