1

我正试图让我的一些通过 bash 重定向记录的应用程序变得非常容易登录。基本上,我有一个将 STDIN 读入缓冲区的 C 程序。它读取此缓冲区,并且每当遇到换行符时,它将收集到的输出写入文件。

该程序的不同之处在于它不会使文件保持打开状态。每次遇到新行时,它都会打开它以进行追加。这与 logrotate 实用程序配合得很好,但我想知道是否存在某种可怕的不可预见的问题,我没有考虑到稍后会遇到的问题。

仅在此实用程序中实现信号处理并让 logrotate 向其发送 SIGHUP 会更好吗?我正在做的事情有可怕的性能损失吗?

所以通常你会在哪里做:

./app >> output.log

使用记录器实用程序,您可以:

./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;
}

谢谢!

4

1 回答 1

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

于 2012-08-08T00:19:48.647 回答