如何将日期字符串添加到连续写入的日志文件的每一行

Posted

技术标签:

【中文标题】如何将日期字符串添加到连续写入的日志文件的每一行【英文标题】:How to add date string to each line of a continuously written log file 【发布时间】:2011-09-16 13:37:23 【问题描述】:

有一个持续写入日志文件的长时间运行程序 - 不考虑任何缓冲问题,如何使用 linux 脚本向写入该文件的每一行添加一个日期字符串?

我会想象这样的事情:

tail -f logfile | ADD_DATE_TO_EACH_LINE > logfile2

输入会是这样的:

abc
def
ghi
jkl

输出应该类似于:

2011-06-16 18:30:59 abc
2011-06-16 18:31:00 def
2011-06-16 18:35:21 ghi
2011-06-16 18:40:15 jkl

【问题讨论】:

【参考方案1】:

我看到elsewhere 的一个建议,如果及时性很重要,应该避免从 BASH 调用其他程序并使用内置:

printf '%(%F %T)T\n'

%T 是来自date(参见man date)、AFAICT 的相同格式字符串。 示例:

output="Err, Miss Crabapple, I just ate my worm!"; \
printf '\n%(%F %s)T'; printf "%s \n" " $output"

将输出:

2021-03-28 1616894012 Err, Miss Crabapple, I just ate my worm!

我刚刚注意到对该链接的评论建议使用gawk for timestamp top speeds。

【讨论】:

【参考方案2】:

有一个工具可用于此目的,它是ts(请参阅man ts

例如,使用您的日志文件:

tail -f logfile | ts '%Y-%m-%d %H:%M:%S'

当然,也适用于任何在标准输出上编写的软件:

./blabla | ts '%Y-%m-%d %H:%M:%S'

如果需要,您可以添加亚秒级精度,使用 %.S 代替 %S

【讨论】:

ts 在 Ubuntu 上的包 moreutils 中,类似的,通过 sudo apt install moreutils 安装。【参考方案3】:

或者你可以使用 python ...

cat /dev/urandom | python -c "from __future__ import print_function; import sys; import datetime; map(lambda x: print(datetime.datetime.now(), x), [line for line in sys.stdin.readlines()])"

或者使用gnu屏幕

screen -a ls -lh -L -U -X command

首先,您需要在 ~/.screenrc 上启用日志记录和时间戳

logfile /tmp/screen-%S-%n.log
logtstamp on

【讨论】:

【参考方案4】:

你可以试试这个

cat /etc/motd | xargs -d"\n" -I  date +"%Y-%m-%d %H:%M:%S "

示例输出:

2013-02-26 15:13:57 2013-02-26 15:13:57 Debian GNU/Linux 系统包含的程序是免费软件; 2013-02-26 15:13:57 每个程序的确切分配条款在 2013-02-26 15:13:57 /usr/share/doc/*/copyright 中的单个文件。 2013-02-26 15:13:57 2013-02-26 15:13:57 Debian GNU/Linux 附带绝对没有保证,在某种程度上 2013-02-26 15:13:57 适用法律允许。

【讨论】:

@Vouze 您可以在两者之间使用sed 来解决这个问题,或者实际上而不是useless use of catsed 's/%/%%/g' /etc/motd | xargs ...【参考方案5】:

使用 perl:

command 2>&1 | perl -pe 'print scalar(localtime()), " ";'

呆呆的:

command 2>&1 | awk ' print strftime(), $0; fflush() '

对于您的具体示例,将 command 替换为 tail -f logfile。或者,也许您可​​以将原始程序的 stdout/stderr 重定向到上述管道。

【讨论】:

你从这个答案中得到的好处是它不会为每一行产生一个新的日期进程,但两者都很好。 perl -pne ??你不想要-n-p 谢谢!我真的不知道perl。我只是从互联网上剪切和粘贴其他杂物。 :) 上次我真正使用 perl 是在十多年前!我通常使用上面提供的 gawk 答案,但也包括 perl 以防 OP 不在 linux 上。 @StevePrentice 当我执行第一个命令时,它挂起。我正在运行 tail -f test-text.rtf 2>&1 | perl -pe 'print scalar(localtime()), " ";' > test-text.rtf 知道为什么吗?【参考方案6】:

试试

tail -f logfile | while read line; do echo `date` "$line" ; done

【讨论】:

+1 不过只有一点:使用date +"%y-%m-%d %H:%M:%S" 而不是简单的date 会得到他期望的准确输出;最后,您还可以将重定向添加到输出文件。 (实际上是两个音符):) 谢谢,这行得通。如果您将" 符号添加到$line,shell 将不会将* 符号扩展到目录内容;) 这个解决方案的问题是:当给'while read line'循环的输入缓冲区太大时,一些行会被截断。【参考方案7】:

有点冗长,但这是我想出的:

tail -f logfile | sed -u 's/%/%%/g' | xargs -I  date +"%Y-%m-%d %H:%M:%S "

【讨论】:

这是一个非常好的解决方案。但是sed -u 's/%/%%/g' 是干什么用的? % 标志对xargs 有特殊含义吗? @bmk 此方法通过将整行放入date 的格式字符串中来工作,其中% 具有特殊含义。例如,如果日志中的行包含%Y,那么它将被替换为年份,但将其更改为%%Ysed 将正确输出%Y 我要补充一点:如果输入流中有单引号 ('),xargs 会以以下错误消息终止:xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option 因此我将命令更改为tail -f logfile | sed -u 's/%/%%/g' | tr "\n" "\0" | xargs -0 -I date +"%Y-%m-%d %H:%M:%S "【参考方案8】:

您能否配置长时间运行的程序将其输出写入标准输出而不是日志文件?在这种情况下,很容易将输出通过管道传输到一个脚本,该脚本首先写入当前时间戳,然后写入条目。

如果这是不可能的,它可能有助于定期(例如每秒)读取日志文件内容,将每一行复制到另一个文件(添加当前时间戳)然后删除日志文件。但是,这可能会导致在读取和删除文件之间写入的日志文件条目丢失:(

【讨论】:

我无法将程序配置为记录到标准输出,因为它是(分别可以用作)交互式程序。但在我看来,实际执行tail -f 或多或少与直接写入标准输出相同。实际上我正在寻找那个“首先写入当前时间戳然后写入条目的脚本”。 你可以使用 FIFO。该程序会将所有内容写入命名管道(fifo),您可以同时从中读取,附加日期并写入真正的日志文件。

以上是关于如何将日期字符串添加到连续写入的日志文件的每一行的主要内容,如果未能解决你的问题,请参考以下文章

用linux c语言编写 为一个文件里面的内容的每一行添加一个指定的字符

如何将在从控制台获取的 URL 中找到的特定字符串替换为在 Ruby 文本文件中写入的每一行中找到的文件内容?

使用 Node.js 将一行写入 .txt 文件

将带有日期的 stderr 重定向到来自 Cron 的日志文件

mysql 如何获取数据表中离当前日期最近的数据

如何将源文件名添加到 Spark 中的每一行?