Python 3 app 运行 in docker-compose 将不会使用 print('text', end='\r') 打印

Python 3 app running in docker-compose will not print using print('text', end='\r')

希望得到有关 解决方法 修复 的建议:

Python 3.9 运行 在 docker-compose 3.8 中使用 CMD [ "python3", "-u", "app.py" ]

print('text', end='\r', flush=True) 不会 打印到终端 - 希望打印出来。

print('text', flush=True) 将打印到终端。

是的,同时使用"python3", "-u"flush=True有点过分了。‍♂️

print() 函数将打印消息中的所有字符,然后在打印后附加结束字符。如果你省略 end= 它默认为换行符(\n 在 nix 上)。 \r 字符将光标移动到 相同 行的开头。

所以让我们看一下 python 解释器中的几种情况:

# print 'text' followed by \r (move to beginning of line) followed by newline
>>> print('text\r')
asdf
>>>

在这个例子中,打印text,然后光标移动到同一行的开头,然后打印默认的换行符移动到下一行。最后,python 打印其提示。

# print 'text' followed by \r followed by nothing
>>> print('text', end='\r')
>>>

在这个例子中,打印了text,光标移动到同一行的开头,然后命令结束,解释器打印提示>>>覆盖text 已打印。

# print 'text followed by \r followed by nothing (alternate)
>>> print ('text\r', end='')
>>>

以上与前面的例子相同

当您从终端使用 python 运行 脚本时,情况非常相似,除了 python 解释器打印提示外,您的 shell 是程序执行后打印提示。

很难在此处提出“修复”建议,因为不清楚您实际想要完成什么。

我认为你只需要在前面加上 \r,例如:

import time

for i in range(10):
    print('\rcount {}'.format(i), end='')
    time.sleep(1)

在这里您会看到消息 count n,每秒都在变化。

docker-compose up 的输出聚合 1 并且有效地 line-buffered 2 (参见 示例日志),这意味着它仅在看到 \n 时打印。关于此行为还有其他轶事 3,4 \r

可以看到其实是运行 docker-compose run app 5.

打印的

参考文献:

  1. https://docs.docker.com/compose/reference/up/
  2. https://eklitzke.org/stdout-buffering
  3. https://github.com/docker/compose/issues/1549#issuecomment-745086053
  4. https://docs.docker.com/compose/faq/#whats-the-difference-between-up-run-and-start

解决方法

1。 运行直接单个应用

运行docker-compose run app,如上所述。

docker-compose run 的输出直接进入终端的标准输出。

2。将输出复制到 volume-mounted 文件并观看

tee CMD 中的输出到已安装卷中的文件,然后 tail -F 该文件。

touch app.log
docker-compose up & tail -F app.log

(Ctrl+C 退出 tail -F app.log。)

示例文件

app.py:

from time import sleep
  
for i in range(10):
    print('text: {}'.format(i), end='\r')
    sleep(0.3)

Dockerfile:

FROM python:3.7-alpine
WORKDIR /app

COPY . .
# CMD [ "python3", "-u", "app.py" ]
CMD python3 -u app.py > app.log

docker-compose.yml:

version: "3.9"
services:
  app:
    build: .
    volumes:
      - ./:/app

示例日志

来自 docker-compose up 无解决方法:

==> /var/lib/docker/containers/xxx/xxx-json.log <==
{"log":"text: 0\rtext: 1\rtext: 2\rtext: 3\rtext: 4\rtext: 5\rtext: 6\rtext: 7\rtext: 8\rtext: 9\r","stream":"stdout","time":"xxx"}

因此,print('text: 0\rtext: 1\rtext: 2\rtext: 3\rtext: 4\rtext: 5\rtext: 6\rtext: 7\rtext: 8\rtext: 9\r') 有效地打印了 text: 9\r.

如何在 macOS 中查看日志

  1. 使用 nc -U ~/Library/Containers/com.docker.docker/Data/debug-shell.sock 在 VM 中打开一个 shell。
    参考:https://docs.docker.com/desktop/mac/release-notes/2.x/#docker-desktop-community-2400
  2. 运行 tail /var/lib/docker/containers/*/*.log.