使用 Bash 脚本进行日志轮换
我有以下问题:
我有一个应用程序,它不断向 stderr 和 stdout 生成输出。该应用程序的输出被捕获在日志文件中(该应用程序被重定向为: &> log.txt
)。我没有任何选项来为此生成适当的日志记录。
现在,我有一个 cron 作业,它每小时运行一次,除了做其他事情之外,它还尝试通过将其复制到 log.txt.1 来轮换上面的日志文件,然后创建一个空文件并将其复制到 log.txt
它看起来像:
cp log.txt log.txt.1
touch /tmp/empty
cp /tmp/empty log.txt
问题是,应用程序仍在写入它,因此我在 log.txt.1 中得到一些非常奇怪的东西,它以很多垃圾字符开头,实际的日志文件是在最后的某个地方。
您是否知道如何针对这种特定情况进行正确的日志轮换(我也尝试过 cat log.txt > log.txt.1
,但不起作用)?对于这个特定的应用程序使用 logrotate 不是一个选项,幕后有一个我可能无法更改的完整机制。
谢谢, f.
I have the following issue:
I have an application, which continuously produces output to stderr and stdout. The output of this application is captured in a logfile (the app is redirected as: &> log.txt
). I don't have any options to produce a proper logging to file for this.
Now, I have a cron job, which runs every hour and beside of doing other things, it also tries to rotate this logfile above, by copying it to log.txt.1 and then creates an empty file and copies it to log.txt
It looks like:
cp log.txt log.txt.1
touch /tmp/empty
cp /tmp/empty log.txt
The problem is, that the application is still writing to it, and because of this I get some very strange stuff in the log.txt.1, it starts with a lot of garbage characters, and the actual log file is somewhere at the end.
Do you have any idea, how to make a correct log rotating for this specific situation (I also tried cat log.txt > log.txt.1
, does not work)? Using logrotate
for this specific application not an option, there is a whole mechanism behind the scenes that I may not change.
Thanks,
f.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
好的,这是一个想法,灵感来自 http://en.wikibooks.org/wiki/Bourne_Shell_Scripting/ Files_and_streams
创建命名管道:
将 stdout 和 stderr 重定向到命名管道:
<前><代码>&> /dev/mypipe
从 mypipe 读取到文件中:
当你需要日志轮换时,杀死猫,轮换日志,然后重新启动猫。
现在,我还没有测试过这个。告诉我们进展如何。
注意:您可以为命名管道指定任何名称,例如 /var/tmp/pipe1 、 /var/log/pipe 、 /tmp/abracadabra 等。只需确保在启动后在日志记录脚本运行之前重新创建管道即可。
或者,不要使用 cat,而是使用一个简单的脚本文件:
此脚本保证每次换行读取都有一个输出。 (cat 可能不会开始输出,直到其缓冲区已满或遇到 EOF)
最终 - 并经过测试 - 尝试
重要提示:请阅读以下评论:下面是@andrew。有几种情况你需要注意。
好吧!终于可以访问我的 Linux 盒子了。操作方法如下:
第 1 步:制作此记录器脚本:
第 2 步:使记录器投入工作:
制作命名管道:
重定向应用程序的 STDOUT 和 STDOUT。 STDERR 到命名管道:
启动记录器:
您可能需要
nohup
上面的内容,使其在注销后仍能生存。完成!
第3步:如果需要logrotate,请暂停记录器:
我建议将上述步骤放入其自己的脚本中。请随意将第二行更改为您想要使用的任何日志旋转方法。
注意:如果您擅长 C 编程,您可能想要编写一个简短的 C 程序来执行
recorder.sh
的功能。编译的 C 程序肯定会比 nohup 分离的 bash 脚本更轻。注释 2: David Newcomb 在评论中提供了有用的警告:当记录器未运行时,写入管道将被阻塞,并且可能< em>导致程序不可预测地失败。确保录音机关闭(或旋转)的时间尽可能短。
因此,如果您可以确保旋转确实很快,您可以替换
睡眠
(仅接受整数值的内置命令)与/bin/sleep
(接受浮点值的程序)并将睡眠周期设置为0.5
或更短。Okay, here's an idea, inspired by http://en.wikibooks.org/wiki/Bourne_Shell_Scripting/Files_and_streams
make a named pipe:
redirect stdout and stderr to the named pipe:
read from mypipe into a file:
when you need to log-rotate, kill the cat, rotate the log, and restart the cat.
Now, I haven't tested this. Tell us how it goes.
Note: you can give the named pipe any name, like /var/tmp/pipe1 , /var/log/pipe , /tmp/abracadabra , and so on. Just make sure to re-create the pipe after booting before your logging-script runs.
Alternatively, don't use cat, but use a simple script file:
This script guarantees an output for every newline read. (cat might not start outputting until its buffer is full or it encounters an EOF)
Final -- and TESTED -- attempt
IMPORTANT NOTE: Please read the comments from @andrew below. There are several situations which you need to be aware of.
Alright! Finally got access to my Linux box. Here's how:
Step 1: Make this recorder script:
Step 2: put the recorder into work:
Make a named pipe:
Redirect your application's STDOUT & STDERR to the named pipe:
Start the recorder:
You might want to
nohup
the above to make it survive logouts.Done!
Step 3: If you need to logrotate, pause the recorder:
I suggest putting the above steps into its own script. Feel free to change the 2nd line to whatever log-rotating method you want to use.
Note : If you're handy with C programming, you might want to make a short C program to perform the function of
recorder.sh
. Compiled C programs will certainly be lighter than a nohup-ed detached bash script.Note 2: David Newcomb provided a helpful warning in the comments: While the recorder is not running then writes to the pipe will block and may cause the program to fail unpredictably. Make sure the recorder is down (or rotating) for as short time as possible.
So, if you can ensure that rotating happens really quickly, you can replace
sleep
(a built-in command which accepts only integer values) with/bin/sleep
(a program that accepts float values) and set the sleep period to0.5
or shorter.首先,你真的不应该在这里重新发明方轮。您的同事可能反对按自动应用的每日计划轮换日志到
/etc/logrotate.d/
中的所有脚本 - 这可以通过将脚本放置在其他地方来避免。现在,日志轮换的标准方法(在
logrotate
) 也可以由任何其他设施实施。例如,这是 bash 中的示例实现:最后一项是通过发送 SIGHUP 或(不太常见)SIGUSR1 并在守护进程中使用信号处理程序来替换相应的文件描述符或变量来完成的。这样,切换是原子的,因此日志记录可用性不会中断。在 bash 中,这看起来像:
另一种方法是让写入程序本身在每次写入时跟踪日志大小并进行轮换。这限制了您可以写入的位置以及程序本身支持的循环逻辑的选择。但它的优点是作为一个独立的解决方案,并在每次写入时检查日志大小,而不是按计划检查日志大小。许多语言的标准库都有这样的功能。作为一种嵌入式解决方案,这是在 Apache 的
rotatelogs
:First of all, you really should not reinvent the square wheel here. Your peers are probably against rotating the logs on daily schedule which automatically applies to all scripts in
/etc/logrotate.d/
- this can be avoided by placing the script elsewhere.Now, the standard approach to log rotation (that is implemented in
logrotate
) can be implemented by any other facility just as well. E.g. here's a sample implementation inbash
:The last item is done by sending SIGHUP or (less often) SIGUSR1 and having a signal handler in the daemon that replaces the corresponding file descriptor or variable. This way, the switch is atomic, so there's no interruption in logging availability. In bash, this would look like:
The other approach is to make the writing program itself keep track of the log size each time it writes to it and do the rotation. This limits your options in where you can write to and what rotation logic is to what the program itself supports. But it has the benefit of being a self-contained solution and checking the log size at each write rather than on schedule. Many languages' standard libraries have such a facility. As a drop-in solution, this is implemented in Apache's
rotatelogs
:这个周末我写了一个logrotee。如果我之前读过 @JdeBP 的 关于
multilog
的精彩答案,我可能不会。我专注于它的轻量级并且能够对其输出块进行 bzip2,例如:
不过,还有很多工作要做和测试。
I wrote a logrotee this weekend. I probably wouldn't if I've read @JdeBP's great answer about
multilog
before.I focused on it being lightweight and being able to bzip2 its output chunks like:
There's a lot of to be done and tested yet, though.
您还可以通过 Apacherotatelogs 实用程序传输输出。
或以下脚本:
You can also pipe your output thru Apache rotatelogs utility.
Or following script:
您可以利用
rotatelogs
(此处的文档 )。该实用程序会将脚本的标准输出与日志文件分离,以透明的方式管理轮换。例如:当输出文件达到100M时会自动轮换(可以配置根据时间间隔轮换)。
You can leverage
rotatelogs
(docs here). This utility will decouple your script's stdout from the log file, managing the rotation in a transparent way. For example:will automatically rotate the output file when it reaches 100M (can be configured to rotate based on a time interval).
最简单的脚本可能是这样的rotatelog.sh:
您可以使用如下内容:
A simplest script could be something like this rotatelog.sh:
You can use like: