在 Golang 中读取正在被写入的文件时,可以使用 os.OpenFile 函数。

huangapple go评论65阅读模式
英文:

Reading os.OpenFile in Golang while still being written?

问题

我有一段代码,在执行系统命令时会写入日志文件。例如:

logfile, err := os.OpenFile(THIS_LOG_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
    return err
}
cmd.Stderr = logfile
cmd.Stdout = logfile

go func() {
    err := cmd.Run()
    if err != nil {
        // 在这里记录错误日志
    }
}()

在 "// 在这里记录" 这一行,我想将内容输出到标准日志记录器(standard logger),除了之前指定的日志文件目标之外。有没有办法将其捕获到内存中?或者我应该将所有内容写入内存缓冲区,并在最后刷新?

为了澄清,通过在内存中捕获命令的输出,我可以解析它并在运行的程序中采取相应的操作(处理错误等)。当我写入日志文件时,这些信息就会丢失。

我的问题是,理论上来说,我可以从刚刚写入的文件中读取它,但这似乎是浪费资源的(而且如果命令失败,容易出错)。

英文:

I have code that is writing to a logfile while executing a system command. E.g.

	logfile, err := os.OpenFile(THIS_LOG_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		return err
	}
	cmd.Stderr = logfile
	cmd.Stdout = logfile

	go func() {
		err := cmd.Run()
		if err != nil {
			// WANT TO LOG ERROR HERE
		}
	}()

At the "// WANT TO LOG" line, I'd like to output the content to the standard logger, in addition to the previously assigned logfile destination. Is there a way to capture this in memory? Or should I just write everything to an in-memory buffer and flush at the end?

To clarify, in capturing the output of the command in memory, I can parse it and take action in the running program (handling errors/etc). When I write to the log file, that information is lost.

My issue is that, theoretically, I could read that back in from the file I just wrote, but that seems wasteful (and prone to failure if the command failed).

答案1

得分: 1

如果我理解正确,您想在执行shell命令时将stdout/stderror的内容写入文件。

由于stdout和stderror实现了ReadCloser接口,您可以通过io.MultiReader将它们合并,并使用io.Copy从源到目标进行操作。

以下代码片段实现了这个流程:

package main

import (
	"io"
	"log"
	"os"
	"os/exec"
)

func main() {
	// 准备命令
	cmd := exec.Command("your-shell-command.sh")

	// 获取stdout和stderr流
	erc, err := cmd.StderrPipe()
	if err != nil {
		log.Fatalln("无法获取stderr读取器:", err)
	}
	orc, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatalln("无法获取stdout读取器:", err)
	}

	// 合并stdout和stderror的ReadCloser
	rc := io.MultiReader(erc, orc)

	// 准备写入器
	f, err := os.Create("output.log")
	if err != nil {
		log.Fatalln("无法创建文件")
	}
	defer f.Close()

	// Command.Start启动一个新的goroutine
	if err := cmd.Start(); err != nil {
		log.Println("无法启动命令")
	}

	// 添加TeeReader
	if _, err := io.Copy(f, rc); err != nil {
		log.Fatalf("无法将流写入文件:%s", err)
	}

	if err := cmd.Wait(); err != nil {
		log.Println("等待命令执行时出错:", err)
	}
}

这段代码将执行您的shell命令,并将stdout和stderr的内容合并写入名为"output.log"的文件中。

英文:

If I understand correctly, you want to write the content of stdout/stderror to a file while executing a shell command.

Since stdout and stderror are implemented the ReadCloser interface, you can merge them by io.MultiReader and perform io.Copy from source to destination.

The following snippet implements the pipeline

package main

import (
	"io"
	"log"
	"os"
	"os/exec"
)

func main() {
	// prepare the command
	cmd := exec.Command("your-shell-command.sh")

	// get the stdout and stderr stream
	erc, err := cmd.StderrPipe()
	if err != nil {
		log.Fatalln("Failed to get stderr reader: ", err)
	}
	orc, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatalln("Failed to get stdout reader: ", err)
	}

	// combine stdout and stderror ReadCloser
	rc := io.MultiReader(erc, orc)

	// Prepare the writer
	f, err := os.Create("output.log")
	if err != nil {
		log.Fatalln("Failed to create file")
	}
    defer f.Close()
	// Command.Start starts a new go routine
	if err := cmd.Start(); err != nil {
		log.Println("Failed to start the command")
	}

	// add the TeeReader.
	var buf bytes.Buffer 
	tr := io.TeeReader(rc, &buf) 
	if _, err := io.Copy(f, tr); err != nil { 
		logger.Fatalf("Failed to stream to file: %s", err) 
	}


	if err := cmd.Wait(); err != nil {
		log.Println("Failed to wait the command to execute: ", err)
	}
}

huangapple
  • 本文由 发表于 2022年3月9日 09:26:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/71403296.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定