英文:
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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论