2

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!

0 Answers0