syn*_*pis 7 c linux logging logrotate named-pipes
我想知道在对从不关闭文件描述符的进程进行 logrotate 时我有什么选择。我知道“重新启动服务”和复制截断选项。但是,假设重新启动进程是不可取的,应用程序不会响应 SIGHUP,并且由于潜在的数据丢失而无法接受复制截断,我不确定还剩下什么选项。
我想到的一个解决方案是在进程即将登录的地方已有一个命名管道。让另一个实用程序从该管道读取(复制到另一个日志文件)并让它对 SIGHUP 信号(来自 logrotate)做出反应。
现在我的问题是,是否已经有一个实用程序可以用于此目的?如果没有,为什么?这种方法有本质上的错误吗?
为了测试这一点,我做了 2 项测试,一项是通过复制截断确认数据丢失,另一项是测试我的“命名管道 + 实用程序”方法:
演示复制截断损失:
应用程序.c
int main(int argc, char *argv[]) {
FILE* f = fopen("log.txt", "a");
int cnt = 0;
for (int i = 0; i < 1000000; i++) {
for (int j = 0; j < 100; j++) {
fprintf(f, "Logging line %d\n", cnt);
cnt++;
}
fflush(f);
}
fflush(f);
fclose(f);
printf("Wrote %d lines\n", cnt);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
以及附带的 logrotate 配置:
$cat /etc/logrotate.d/logexp
/home/synepis/git/logexp/log.txt {
size 20M
create 700 synepis users
rotate 4
copytruncate
}
Run Code Online (Sandbox Code Playgroud)
最后,我运行了该应用程序,在运行期间我通过以下方式手动启动了 logrotate 几次:
logrotate --force /etc/logrotate.d/logexp
Run Code Online (Sandbox Code Playgroud)
应用程序结果:
./app
Wrote 100000000 lines
Run Code Online (Sandbox Code Playgroud)
日志行数:
$ cat log.txt* | wc -l
69091700
Run Code Online (Sandbox Code Playgroud)
日志实用方法:
我实现了一个简单的实用程序“loghup”,它创建一个命名管道“log.txt”,然后将其简单地读取到“safe_log.txt”。最后,它通过重新打开文件来响应 SIGHUP(从而开始新的日志轮换)。
loghup.c
int sighup = 0;
void sig_handler(int signo) {
if (signo == SIGHUP)
sighup = 1;
}
void do_piping(char *input, char *output) {
int fi = open(input, O_RDONLY);
int fo = open(output, O_WRONLY | O_CREAT, 0644);
size_t ret;
char buff[4096];
while((ret = read(fi, buff, 4096)) != 0) {
if(ret == -1 && errno == EINTR) { // Retry later
continue;
} else if (ret == -1) {
break; // Error occured
}
write(fo, buff, ret);
if (sighup) { // Reopen output log file on SIGHUP
close(fo);
fo = open(output, O_WRONLY | O_CREAT, 0644);
sighup = 0;
}
}
close(fo);
close(fi);
}
int main(int argc, char *argv[]) {
char *input_file = argv[1];
char *output_file = argv[2];
signal(SIGHUP, sig_handler); // Setup signal handler
mkfifo(input_file, S_IRUSR | S_IWUSR); // Create named pipe
do_piping(input_file, output_file);
}
Run Code Online (Sandbox Code Playgroud)
带 SIGHUP 的新 logrotate 配置:
$cat /etc/logrotate.d/logexp
/home/synepis/git/logexp/safe_log.txt {
size 20M
create 700 synepis users
rotate 4
postrotate
/bin/kill -SIGHUP $(ps aux | grep "[l]oghup" | awk '{print $2}')
endscript
}
Run Code Online (Sandbox Code Playgroud)
然后我跑了:
./app
./loghup log.txt safe_log.txt
Run Code Online (Sandbox Code Playgroud)
最后强制 logrotate 几次:
$ cat safe_log.txt* | wc -l
100000000
Run Code Online (Sandbox Code Playgroud)