dou9022 2019-07-20 05:17
浏览 86

当在Docker中将PEPI输出时从OS.Stdin读取时被阻止

I'm trying to pipe the output(logs) of a program to a Go program which aggregates/compress the output and uploads to S3. The command to run the program is "/program1 | /logShipper". The logShipper is written in Go and it's simply read from os.Stdin and write to a local file. The local file will be processed by another goroutine and upload to S3 periodically. There are some existing docker log drivers but we are running the container on a fully managed provider and the log processing charge is pretty expensive, so we want to bypass the existing solution and just upload to S3.

The main logic of the logShipper is simply read from the os.Stdin and write to some file. It's work correctly when running on the local machine but when running in docker the goroutine blocked at reader.ReadString(' ') and never return.

go func() {
    reader := bufio.NewReader(os.Stdin)
    mu.Lock()
    output = openOrCreateOutputFile(&uploadQueue, workPath)
    mu.Unlock()
    for {
    text, _ := reader.ReadString('
')
    now := time.Now().Format("2006-01-02T15:04:05.000000000Z")
    mu.Lock()
    output.file.Write([]byte(fmt.Sprintf("%s %s", now, text)))
    mu.Unlock()
     }
}()

I did some research online but not find why it's not working. One possibility I'm thinking is might docker redirect the stdout to somewhere so the PIPE not working the same way as it's running on a Linux box? (As looks like it can't read anything from program1) Any help or suggestion why it not working is welcome. Thanks.

Edit: After doing more research I realized it's a bad practice to handle the logs in this way. I should more rely on the docker's log driver to handle the log aggregate and shipping. However, I'm still interested to find out why it's not read anything from the PIPE source program.

  • 写回答

1条回答 默认 最新

  • dpp66953 2019-07-20 14:20
    关注

    I'm not sure about the way the Docker handles output, but I suggest that you extract the file descriptor with os.Stdin.Fd() and then resort to using golang.org/x/sys/unix package as follows:

    // 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)
    
    

    The difference between the long and a short way is that the long way will definitely tell you, if the problem is in the nonblocking state absence or not.

    If this is not the case. Then I have no other ideas personally.

    评论

报告相同问题?

悬赏问题

  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮