docker-py 在生成器挂起时读取容器日志

docker-py reading container logs as a generator hangs

我正在使用 docker-py 以流的形式读取容器日志。通过将 stream 标志设置为 True,如文档中所示。基本上,我遍历我的所有容器并读取它们的容器日志作为生成器并将其写出到如下文件:

for service in service_names:
    dkg = self.container.logs(service, stream=True)
    with open(path, 'wb') as output_file:
        try:
            while True:
                line = next(dkg).decode("utf-8")
                print('line is: ' + str(line))
                if not line or "\n" not in line:  # none of these work
                    print('Breaking...')
                    break
                output_file.write(str(line.strip()))

        except Exception as exc:                  # nor this
            print('an exception occurred: ' + str(exc))

但是,它只读取了第一个服务,并挂在了文件的末尾。它不会跳出循环,也不会引发异常(例如 StopIteration 异常)。根据文档,如果 stream=True 它应该 return 一个生成器,我打印出生成器类型并且它显示为 docker.types.daemon.CancellableStream 所以不要认为它会遵循传统的 python 如果我们到达容器日志生成器的末尾并调用 next()。

如您所见,我已经尝试检查 eol 是否为假或包含换行符,甚至查看它是否会捕获任何类型的异常但没有成功。 还有别的办法吗。判断是否到达服务流的末尾,跳出while循环,继续写下一个服务?之所以要用流,是因为大量的数据导致我的系统 运行 内存不足,所以我更喜欢使用生成器。

问题是流在容器停止之前并没有真正停止,它只是暂停等待下一个数据到达。为了说明这一点,当它挂在第一个容器上时,如果您对该容器执行 docker stop,您将得到一个 StopIteration 异常,并且您的 for 循环将移动到下一个容器的日志。

您可以使用 follow = False 告诉 .logs() 不要关注日志。奇怪的是,文档说默认值为 False,但事实似乎并非如此,至少对于流媒体而言并非如此。

我遇到了和你一样的问题,这段使用 follow = False 的代码摘录不会挂在第一个容器的日志中:

import docker
client = docker.from_env()
container_names = ['container1','container2','container3']
for container_name in container_names:
    dkg = client.containers.get(container_name).logs(stream = True, follow = False)
    try:
      while True:
        line = next(dkg).decode("utf-8")
        print(line)
    except StopIteration:
      print(f'log stream ended for {container_name}')