私は、bash リダイレクトを介してログを記録する一部のアプリを簡単に logrotate できるようにしようとしています。基本的に、STDINをバッファに読み込むCプログラムがあります。このバッファを読み取り、改行に遭遇するたびに、収集した出力をファイルに書き込みます。
このプログラムの違いは、ファイルを開いたままにしないことです。新しい行に遭遇するたびに追加するためにそれを開きます。これは logrotate ユーティリティでうまく機能しますが、後で出くわす、私が説明していない恐ろしい予期せぬ問題があるのではないかと思っています。
このユーティリティでシグナル処理を実装し、logrotate に SIGHUP を送信させるだけの方がよいでしょうか? 私がしていることに恐ろしいパフォーマンスのペナルティがありますか?
したがって、通常は次のようにします。
./app >> output.log
ロガーユーティリティを使用すると、次のことができます。
./app | ./mylogger output.log
私は C が苦手ですが、C のベスト プラクティスについてはあまり詳しくありません。ガイダンスをいただければ幸いです。
ソースは次のとおりです。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define BUFSIZE 1024
#define MAX_WRITE_FAILS 3
/**
* outputs the given content to the specified file.
*/
int file_output(char *filename, char *content, size_t content_length)
{
FILE *fp;
fp = fopen(filename, "a");
content[content_length + 1] = '\0';
if(fp == NULL) return errno;
fwrite(content, sizeof(char), content_length, fp);
fclose(fp);
return 0;
}
/**
* Loops over STDIN and whenever it finds a newline, sends the current content
* buffer to the file specified on the command line.
*/
int main(int argc, char *argv[])
{
int i;
char buffer[BUFSIZE];
char *content = malloc(sizeof(char) * BUFSIZE);
size_t content_size = 0;
int content_buf_size = BUFSIZE;
int write_failures = 0;
char *file;
if(argc < 2)
{
fprintf(stderr, "Usage: logger <file>");
exit(1);
}
file = argv[1];
// loop over STDIN
while(fgets(buffer, BUFSIZE, stdin))
{
int output_err;
int buflength = strlen(buffer);
// loop over character for character, searching for newlines and
// appending our buffer to the output content as we go along
for(i = 0; i < buflength; i++)
{
char *old = content;
// check if we have a newline or end of string
if(buffer[i] == '\n' || buffer[i] == '\0' || (i != (buflength - 1) && buffer[i] == '\r' && buffer[i+1] == '\n'))
{
content[content_size] = '\n';
output_err = file_output(file, content, content_size + 1);
if(output_err == 0)
{
// success! reset the content size (ie more or less resets
// the output content string)
content_size = 0;
write_failures = 0;
}
else
{
// write failed, try to keep going. this will preserve our
// newline so that the next newline we encounter will write
// both lines (this AND and the next).
content_size++;
write_failures++;
}
}
if(write_failures >= MAX_WRITE_FAILS)
{
fprintf(stderr, "Failed to write output to file %d times (errno: %d). Quitting.\n", write_failures, output_err);
exit(3);
}
if(buffer[i] != '\n' && buffer[i] != '\r' && buffer[i] != '\0')
{
// copy buffer into content (if it's not a newline/null)
content[content_size] = buffer[i];
content_size++;
}
// check if we're pushing the limits of our content buffer
if(content_size >= content_buf_size - 1)
{
// we need to up the size of our output buffer
content_buf_size += BUFSIZE;
content = (char *)realloc(content, sizeof(char) * content_buf_size);
if(content == NULL)
{
fprintf(stderr, "Failed to reallocate buffer memory.\n");
free(old);
exit(2);
}
}
}
}
return 0;
}
ありがとう!