分别处理 stdout 和 stderr 添加时间戳:顺序错误
Processing stdout and stderr separately adding a timestamp: Wrong order
这些是我的测试文件:
std-test.sh:
#!/bin/bash
for i in {0..20}
do
number=$RANDOM
let "number %= 10"
if [ $number -le 6 ]
then
echo $i;
else
echo $i 1>&2;
fi
done
process.sh:
#!/bin/bash
while read line; do
[[ = "err" ]] && echo "$(date +%s%3N) $line" >> stderr;
[[ = "out" ]] && echo "$(date +%s%3N) $line" >> stdout;
done
std-test.sh
创建包含行号的 20 行,并且 process.sh
能够在通过管道传输到它时读取另一个命令输出,而当 [=19= 时它保存到 stderr
] 作为参数传递给它,并在传递 out
时传递给 stdout
。我用来测试整个事情的命令是:
./std-test.sh 2> >(./process.sh err) > >(./process.sh out)
(取自here)。我的测试输出如下:
stdout:
1486297129986 0
1486297129987 1
1486297129988 2
1486297129988 3
1486297129989 4
1486297129990 6
1486297129991 7
1486297129991 8
1486297129992 9
1486297129993 10
1486297129993 11
1486297129994 12
1486297129995 14
1486297129995 17
1486297129996 18
stderr:
1486297129986 5
1486297129987 13
1486297129987 15
1486297129988 16
1486297129989 19
1486297129990 20
当我尝试解析输出时,我意识到 stderr
和 stdout
的顺序完全混乱了。例如,为什么 stderr
中的 5 出现在 stdout
中的 1 之前?还是 1 之后是 13?我在这里犯了什么错误,我该如何解决?
编辑 #1: 我知道我可以将 stderr 和 stdout 直接传送到文件,但是 process.sh
会将结果卷曲到远程服务器。将其保存到文件只是一种 POC。
编辑 #2: 我实际上是在尝试以编程方式为 docker 日志添加时间戳和处理。
更新:
从评论来看,OP 似乎真的在尝试为 运行 应用程序的输出添加时间戳并将其记录在 docker 容器中。
docker logs -t
已经这样做了,是工作的最佳工具。
原回答:
可能是因为您在每一行上都加上了处理时间而不是实际生成时间的时间戳?
当您 运行 该命令时,您启动了 3 个进程,并非所有进程都 运行 并行。
这些进程并不是 运行 以真正并行的方式运行,它们可以在内核需要时被抢占。因为 stdout 多 longer/processing 行,所以它更有可能被抢占,然后在稍后恢复。这将解释时间戳。
您真正需要线路上的时间戳有什么用?您只是想在字里行间排序,还是想要真实的时间戳?
编辑:正如@Sven Festersen 在评论中指出的那样,也可能是因为 stdout is buffered when piped by default.
这些是我的测试文件:
std-test.sh:
#!/bin/bash
for i in {0..20}
do
number=$RANDOM
let "number %= 10"
if [ $number -le 6 ]
then
echo $i;
else
echo $i 1>&2;
fi
done
process.sh:
#!/bin/bash
while read line; do
[[ = "err" ]] && echo "$(date +%s%3N) $line" >> stderr;
[[ = "out" ]] && echo "$(date +%s%3N) $line" >> stdout;
done
std-test.sh
创建包含行号的 20 行,并且 process.sh
能够在通过管道传输到它时读取另一个命令输出,而当 [=19= 时它保存到 stderr
] 作为参数传递给它,并在传递 out
时传递给 stdout
。我用来测试整个事情的命令是:
./std-test.sh 2> >(./process.sh err) > >(./process.sh out)
(取自here)。我的测试输出如下:
stdout:
1486297129986 0
1486297129987 1
1486297129988 2
1486297129988 3
1486297129989 4
1486297129990 6
1486297129991 7
1486297129991 8
1486297129992 9
1486297129993 10
1486297129993 11
1486297129994 12
1486297129995 14
1486297129995 17
1486297129996 18
stderr:
1486297129986 5
1486297129987 13
1486297129987 15
1486297129988 16
1486297129989 19
1486297129990 20
当我尝试解析输出时,我意识到 stderr
和 stdout
的顺序完全混乱了。例如,为什么 stderr
中的 5 出现在 stdout
中的 1 之前?还是 1 之后是 13?我在这里犯了什么错误,我该如何解决?
编辑 #1: 我知道我可以将 stderr 和 stdout 直接传送到文件,但是 process.sh
会将结果卷曲到远程服务器。将其保存到文件只是一种 POC。
编辑 #2: 我实际上是在尝试以编程方式为 docker 日志添加时间戳和处理。
更新:
从评论来看,OP 似乎真的在尝试为 运行 应用程序的输出添加时间戳并将其记录在 docker 容器中。
docker logs -t
已经这样做了,是工作的最佳工具。
原回答:
可能是因为您在每一行上都加上了处理时间而不是实际生成时间的时间戳?
当您 运行 该命令时,您启动了 3 个进程,并非所有进程都 运行 并行。
这些进程并不是 运行 以真正并行的方式运行,它们可以在内核需要时被抢占。因为 stdout 多 longer/processing 行,所以它更有可能被抢占,然后在稍后恢复。这将解释时间戳。
您真正需要线路上的时间戳有什么用?您只是想在字里行间排序,还是想要真实的时间戳?
编辑:正如@Sven Festersen 在评论中指出的那样,也可能是因为 stdout is buffered when piped by default.