You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Rust子进程日志分存独立文件并添加进程标识前缀?

解决方案

要实现你的两个需求(子进程日志分文件存储、终端输出带进程编号前缀),可以通过修改std::process::Command的输出重定向逻辑来完成,以下是具体实现:

1. 将每个子进程日志写入独立文件

在创建子进程时,为每个进程指定独立的日志文件作为stdout和stderr的输出目标,代码示例如下:

use std::fs::File;
use std::process::Command;

fn main() {
    let args = ["run", "--features", "my-feat"];
    for i in 0..3 {
        // 创建对应编号的日志文件
        let log_file = File::create(format!("testfile{}.log", i + 1))
            .expect(format!("Failed to create testfile{}.log", i + 1).as_str());
        
        // 配置子进程,将stdout和stderr重定向到日志文件
        let _process = Command::new("cargo")
            .env("RUST_LOG", "trace") // 传递日志环境变量
            .args(&args)
            .stdout(log_file.try_clone().expect("Failed to clone file handle"))
            .stderr(log_file)
            .spawn()
            .expect("Failed to spawn child process");
    }
}

这样每个子进程的标准输出和错误都会被写入对应的testfile1.log、testfile2.log、testfile3.log文件,无需再用shell的重定向命令。

2. 终端输出带进程编号前缀

如果需要在终端直接查看带前缀的输出,需要捕获子进程的输出流,在父进程中为每一行添加前缀后再打印。这里需要用线程来异步处理每个子进程的输出,避免阻塞:

use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
use std::thread;

fn main() {
    let args = ["run", "--features", "my-feat"];
    let mut handles = vec![];

    for i in 0..3 {
        // 配置子进程,捕获stdout和stderr
        let mut child = Command::new("cargo")
            .env("RUST_LOG", "trace")
            .args(&args)
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .expect("Failed to spawn child process");

        // 处理stdout
        let stdout = child.stdout.take().expect("Failed to take stdout");
        let handle_stdout = thread::spawn(move || {
            let reader = BufReader::new(stdout);
            for line in reader.lines() {
                if let Ok(line) = line {
                    println!("[{}] {}", i, line);
                }
            }
        });

        // 处理stderr
        let stderr = child.stderr.take().expect("Failed to take stderr");
        let handle_stderr = thread::spawn(move || {
            let reader = BufReader::new(stderr);
            for line in reader.lines() {
                if let Ok(line) = line {
                    eprintln!("[{}] {}", i, line); // 错误输出到stderr
                }
            }
        });

        handles.push((child, handle_stdout, handle_stderr));
    }

    // 等待所有子进程和线程完成
    for (mut child, handle_stdout, handle_stderr) in handles {
        let _ = child.wait();
        let _ = handle_stdout.join();
        let _ = handle_stderr.join();
    }
}

这段代码会为每个子进程的stdout和stderr输出行添加[0]、[1]、[2]的前缀,区分不同子进程的输出。

3. 同时实现日志分文件和终端带前缀输出

如果需要既将日志写入独立文件,又在终端显示带前缀的输出,可以结合上述两种方式,在捕获输出后,同时写入文件和终端:

use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::process::{Command, Stdio};
use std::thread;

fn main() {
    let args = ["run", "--features", "my-feat"];
    let mut handles = vec![];

    for i in 0..3 {
        let log_file = File::create(format!("testfile{}.log", i + 1))
            .expect(format!("Failed to create testfile{}.log", i + 1).as_str());
        
        // 配置子进程,捕获stdout和stderr
        let mut child = Command::new("cargo")
            .env("RUST_LOG", "trace")
            .args(&args)
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .expect("Failed to spawn child process");

        // 处理stdout:同时打印到终端和写入文件
        let stdout = child.stdout.take().expect("Failed to take stdout");
        let mut log_file_stdout = log_file.try_clone().expect("Failed to clone file handle");
        let handle_stdout = thread::spawn(move || {
            let reader = BufReader::new(stdout);
            for line in reader.lines() {
                if let Ok(line) = line {
                    let prefixed_line = format!("[{}] {}\n", i, line);
                    println!("{}", prefixed_line.trim_end());
                    let _ = log_file_stdout.write_all(prefixed_line.as_bytes());
                }
            }
        });

        // 处理stderr:同时打印到终端和写入文件
        let stderr = child.stderr.take().expect("Failed to take stderr");
        let mut log_file_stderr = log_file;
        let handle_stderr = thread::spawn(move || {
            let reader = BufReader::new(stderr);
            for line in reader.lines() {
                if let Ok(line) = line {
                    let prefixed_line = format!("[{}] {}\n", i, line);
                    eprintln!("{}", prefixed_line.trim_end());
                    let _ = log_file_stderr.write_all(prefixed_line.as_bytes());
                }
            }
        });

        handles.push((child, handle_stdout, handle_stderr));
    }

    // 等待所有子进程和线程完成
    for (mut child, handle_stdout, handle_stderr) in handles {
        let _ = child.wait();
        let _ = handle_stdout.join();
        let _ = handle_stderr.join();
    }
}

这样运行后,每个子进程的输出会同时带前缀显示在终端,并且写入对应的独立日志文件。

内容的提问来源于stack exchange,提问作者NewToCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:36:00