I was planning on creating a new Layer for logging to gcp LogExplorer. Because we are working in rust, the api for logging is an async
function call.
The tracing Layer
trait exposes on_event
function which is not async, which is where the problem comes in (link here)
I was thinking of ways to solve this, a simple solution which came to my mind was to send the events (the relevant fields) through a channel and then consume the channel on a tokio::spawn where my gcp client can make the grpc calls.
What I have in mind looks roughly like this (glossing over a lot of the details)
fn get_fields_from_event(event: &tracing::Event<'_>) -> LogEntry {
unimplemented!("some code here to convert to a type I can use with grpc coded for logging in gcp");
}
let (events_sender, events_receiver) = futures::channel::mpsc();
impl<S> Layer<S> for CustomLayer
where
S: tracing::Subscriber,
{
fn on_event(
&self,
event: &tracing::Event<'_>,
_ctx: tracing_subscriber::layer::Context<'_, S>,
) {
events_sender.clone().send(get_fields_from_event(event))
}
}
tokio::spawn(async move {
events_receiver.for_each(|event| async {grpc_client.send(event);});
});
Some obvious flaws I see with this approach is:
- if the tokio::spawn silently exists, we might loose logging (I can safeguard against it .. but logging is kinda important for debugging so I would have to restart the process completely or manage the tokio::spawn process)
- tokio::spawn itself feels a bit weird to get async based logging client supported. For some reason this feels a bit weird to me.
Are there any other alternatives or insights I am missing, or some crate which might provide support for working with async logging clients and integrating them in tracing Layer.
Thanks!