How to redirect logs from Command output to tracing?

851 Views Asked by At

I'm adopting tracing as logging tool for my Rust app. I want to have all logs go through tracing. In the future, it will handle send logs to monitoring tool.

The app works by invoking multiple processes. Previously they were printing to stdin and all logs were visible. Those processes ran with Command and tokio::spawn.

I would like to redirect the output from the Command to tracing, but not sure how to do that.

2

There are 2 best solutions below

0
On BEST ANSWER

The result of calling std::Command::output is a Result<Output> and the Output struct has public stdout and stderr Vec<u8> fields.

So like Nikolay wrote, you can can tracing::info! to output each of the field values.

But if the existing code was writing to the stdout and stderr of the app itself, maybe std::Command::spawn was being used? You may want to continue using this spawn method and taking the stdout and stderr from the child as shown in std::process::Child and then actually spawning new threads to read from the stdout and stderr to pass the data to tracing macros like info!.

I doubt the tracing library would have a canned way of doing this because subprocess stdout and stderr could be formatted in so many ways.

But if you expect the output to be short and no parsing is necessary, then passing the stdout and stderr vecs to info! should do the trick as mentioned above.

0
On

As I understand you used println! before and now you want to use tracing.

To activate tracing there are two parts:

  1. where you want to issue the log you replace println! with info! or warning! or other levels, whatever you feel suitable. And you do use tracing::{info, warning} in the beginning. That would not activate tracing as the compiler would just remove these lines if there is no subscriber who is interested in these logs.
  2. So you have to add tracing_subsriber somewhere where your main process start. Before tokio::spawn Simple way
use tracing_subscriber;

tracing_subscriber::fmt::init();

more detailed method

use tracing_subscriber::FmtSubscriber;
use tracing::{Level};

let subscriber = FmtSubscriber::builder()
    .with_max_level(Level::TRACE)
    // ... here you can add file if you want. Or both stdout and file.
    .finish();

See the docs for the configurations.

You can also create spans for more granular tracing but it is not evident that it is what you are looking for.