在Bash脚本中使用日志记录

5

我有一个Bash脚本,需要写日志。目前我使用像下面这样的块:

#log stop request
            {
                local now=$(date +"%a %b %d %Y %H:%M:%S")

                printf "batch stop request successful. \n"
                printf "      Time            :: %s\n" "$now"
                printf "      PID of process  :: %s\n" ${PID[0]}"
            } >> "${mylogfile}"

我的logfile变量将拥有日志文件的名称。

这种方法的问题在于当运行2个或更多实例时,日志往往会因为来自实例的写入交错而混乱。

请注意,我使用了块思想,认为这样会一次性将日志写入文件,从而避免了这个问题。

我看到了Vivek Gite post中的logger命令。但问题在于它不能写入我可以指定的文件,而是写入到了/var/log/message中。

非常感谢任何帮助。

谢谢和问候 Sibi


如果将所有的写入操作都组合成一个单独的 printf 语句,会发生什么?如果不使用多行来输出一条消息,而是只使用一行来输出整个消息,会发生什么? - Jonathan Leffler
仍然无法正常工作,我仍然收到交错的消息。 - Sibi JV
4个回答

3

POSIX(IEEE Std 1003.1-2001)未定义并发write()系统调用发送数据到同一文件的行为,因此您可能会根据平台获得不同的结果。您可以尝试将所有printfs合并成一个,希望这样做可以起作用,但即使如此,也不能保证在将来或不同的平台上也能起作用。

与其使用并发控制和刷新来确保写入顺序,不如将消息发送到第三个进程,该进程将代表所有进程按顺序将日志消息写入文件。事实上,在您引用的文章中,就是使用了loggersyslog进行的。 logger命令不会将消息发送到/var/log/messages。它将日志消息发送到syslog,可以配置syslog将日志消息保存在任何您喜欢的地方。不过,更改此配置通常需要管理员权限。

如果您无法或不想使用syslog,还可以使用netcat作为日志服务器。运行以下命令,将所有脚本的所有传入日志消息复用到文件中(此作业应始终在后台运行,也可以在screen中运行):

nc -luk localhost 9876 > shared_log_file &

(端口9876只是一个例子)并以以下方式登录每个脚本:
printf "Log message\n" > /dev/udp/localhost/9876

您可以使用自定义UDP服务器替代netcat(例如像这个)。

嗨,亚当,感谢你的精彩解释。能否指点一下我在哪里可以找到日志记录器的示例?我在网上尝试了一下,但没有结果。 - Sibi JV
我仍然认为这是不必要的复杂,因为他可以只将相关的printf分组到一个子shell中,并重定向其输出,因为他并不需要特定类型的日志记录行为(例如通过syslog(3)),他只想要“事务性”的写入。 - jkh
嗨,Adam和jkh,JKH是对的,我正在寻找事务性写入。感谢你们两个帮助我。 - Sibi JV
我理解的是他的printf在不相关的进程中发生。如果他可以将所有这些进程分组运行在一个公共shell下,那么你的解决方案确实更简单并且能够完成任务。 - Adam Zalcman
我的printf发生在不相关的进程中。我的脚本是批处理运行的,可以并行运行多个批处理写入同一个日志文件。 - Sibi JV

2

正如你所发现的那样,这个代码块并没有对printf进行任何分组。不过,你可以在子Shell中运行所有命令(放在圆括号之间),然后将子Shell的输出重定向!


1

根据日志的性质,它可能更适合于系统日志而不是私有日志文件。在这种情况下,logger程序可能是手动记录日志的很好替代品。


我喜欢这个建议。没有提到为什么不能使用系统日志。 - Chris
嗨,phasetwenty,我有一个需要在自定义位置记录文件的需求。 - Sibi JV

1
尝试将这3个printf放在一个字符串中,即:
printf "Epsilon batch stop request successful. \n      Time            :: %s\n     PID of process  :: %s\n" "$now"  ${PID[0]}

你仍然可能会得到交错。

为什么不使用${PID}在日志文件名中为每个实例启动自己的日志文件,以使它们保持分离?

 >> "${mylogfile}.${PID}"

编辑

如果你希望使用记录器,请查看手册页:

logger(1) - Linux man page

Name

logger - a shell command interface to the syslog(3) system log module

Synopsis
logger [-isd] [-f file] [-p pri] [-t tag] [-u socket] [message ...]

Description

Logger makes entries in the system log. It provides a shell command interface to the syslog(3) system log module.

Options:

    -i'         Log the process id of the logger process with each line.
    -s' Log the message to standard error, as well as the system log.
    -f file
        Log the specified file.

.....

这看起来就是你想要的。

希望这有所帮助。


嗨,Shellter,我有一个限制,必须记录到一个文件中。有没有办法使用记录器写入自定义文件? - Sibi JV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接