我正在尝试通过管道将程序的输出(日志)传送到Go程序,该程序会聚合/压缩输出并上传到S3。运行该程序的命令是"/program1 | /logShipper“。logShipper是用Go编写的,只需从os.Stdin读取并写入本地文件即可。本地文件将由另一个goroutine处理,并定期上载到S3。有一些现有的docker日志驱动程序,但我们在完全托管的提供者上运行容器,日志处理费用非常昂贵,因此我们希望绕过现有的解决方案,只上传到S3。
logShipper的主要逻辑是简单地从os.Stdin读取和写入某个文件。它在本地机器上运行时工作正常,但在docker中运行时,goroutine在reader.ReadString('\n')处被阻塞,并且再也没有返回。
go func() {
reader := bufio.NewReader(os.Stdin)
mu.Lock()
output = openOrCreateOutputFile(&uploadQueue, workPath)
mu.Unlock()
for {
text, _ := reader.ReadString('\n')
now := time.Now().Format("2006-01-02T15:04:05.000000000Z")
mu.Lock()
output.file.Write([]byte(fmt.Sprintf("%s %s", now, text)))
mu.Unlock()
}
}()我在网上做了一些研究,但找不到为什么它不工作。我在想的一种可能性是,docker可能会将stdout重定向到某个地方,这样管道的工作方式就不同于它在Linux机器上运行的方式?(看起来它不能从program1读取任何东西)欢迎任何关于它不能工作的帮助或建议。谢谢。
编辑:在做了更多的研究后,我意识到以这种方式处理日志是一种糟糕的做法。我应该更多地依靠docker的日志驱动程序来处理日志聚合和传送。但是,我仍然感兴趣的是,为什么它没有从管道源程序中读取任何内容。
发布于 2019-07-20 22:20:22
我不确定Docker处理输出的方式,但我建议您使用os.Stdin.Fd()提取文件描述符,然后使用golang.org/x/sys/unix包,如下所示:
// Long way, for short one jump
// down straight to it.
//
// retrieve the file descriptor
// cast it to int, because Fd method
// returns uintptr
fd := int(os.Stdin.Fd())
// extract file descriptor flags
// it's safe to drop the error, since if it's there
// and it's not nil, you won't be able to read from
// Stdin anyway, unless it's a notice
// to try again, which mostly should not be
// the case
flags, _ := unix.FcntlInt(fd, unix.F_GETFL, 0)
// check if the nonblocking reading in enabled
nb := flags & unix.O_NONBLOCK != 0
// if this is the case, just enable it with
// unix.SetNonblock which is also a
// -- SHORT WAY HERE --
err = unix.SetNonblock(fd, true)long和short way之间的不同之处在于,long的方法肯定会告诉您,问题是否存在于非阻塞状态。
如果不是这样的话。那我个人就没有别的想法了。
https://stackoverflow.com/questions/57122019
复制相似问题