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

kkm*_*our 2 generator python-3.x docker dockerpy

我正在使用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))
Run Code Online (Sandbox Code Playgroud)

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

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

Bri*_*ley 6

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

您可以.logs()使用 告诉不要跟踪日志follow = False。奇怪的是,文档说默认值是 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}')   
Run Code Online (Sandbox Code Playgroud)