通过C程序输出日志输出以便于日志轮换

时间:2012-08-07 23:11:41

标签: c bash logrotate

我正在尝试通过bash重定向来记录我的一些应用程序。基本上,我有一个C程序将STDIN读入缓冲区。它读取此缓冲区,每当遇到换行符时,它会将收集的输出写入文件。

此程序的不同之处在于它不会使文件保持打开状态。它会打开它,以便在每次遇到新行时附加 。这与logrotate实用程序一起工作很好,但是我想知道是否存在某种可怕的不可预见的问题,我没有考虑到我将在以后遇到的问题。

在这个实用程序中实现信号处理是否更好,并且logrotate会向它发送一个SIGHUP?对我正在做的事情是否有可怕的性能惩罚?

通常你要去的地方:

./app >> output.log

使用logger util,您可以:

./app | ./mylogger output.log

虽然我在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;
}

谢谢!

1 个答案:

答案 0 :(得分:3)

由于我在评论中的建议被证明是您所需要的,我将其作为答案添加,并提供更多解释。

如果你有一个无法告诉他们关闭日志文件的日志记录应用程序(通常是通过SIGHUP),你可以使用logrotate.conf中的'copytruncate'选项。

以下是手册页中的说明:

  Truncate  the  original log file in place after creating a copy,
  instead of moving the old log file and optionally creating a new
  one,  It  can be used when some program can not be told to close
  its logfile and thus might continue writing (appending)  to  the
  previous log file forever.  Note that there is a very small time
  slice between copying the file and truncating it, so  some  log-
  ging  data  might be lost.  When this option is used, the create
  option will have no effect, as the old log file stays in  place.

来源:http://linuxcommand.org/man_pages/logrotate8.html