简体   繁体   English

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

[英]Piping log output through a C program for easy log rotation

I'm trying to make it really easy to logrotate some of my apps that log via bash redirection. 我正在尝试通过bash重定向来记录我的一些应用程序。 Basically, I have a C program that reads STDIN into a buffer. 基本上,我有一个C程序将STDIN读入缓冲区。 It reads this buffer, and whenever it encounters a newline, it will write the output it has gathered to a file. 它读取此缓冲区,每当遇到换行符时,它会将收集的输出写入文件。

The difference in this program is that it does not leave the file open. 该程序的不同之处在于它不会使文件保持打开状态。 It opens it for appending each time a new line is encountered . 它会打开它,以便在每次遇到新行时附加。 This works great with the logrotate utility, but I'm wondering if there's some sort of horrible unforseen issue I'm not accounting for that I'll run into later on. 这对于logrotate实用程序很有用,但我想知道是否存在某种可怕的不可预见的问题,我不会考虑到我将在以后遇到的问题。

Is it better just to implement signal handling in this utility and have logrotate send it a SIGHUP? 在这个实用程序中实现信号处理是否更好,并且logrotate会向它发送一个SIGHUP? Are there horrible performance penalties to what I'm doing? 对我正在做的事情是否有可怕的性能惩罚?

So normally where you'd do: 所以通常你要去的地方:

./app >> output.log

With the logger util you do: 使用logger util,您可以:

./app | ./mylogger output.log

Although I'm too bad in C, I'm not very well versed in its best practices. 虽然我在C方面太糟糕了,但我对它的最佳实践并不十分了解。 Any guidance would be greatly appreciated. 任何指导将不胜感激。

Here's the source: 这是来源:

#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;
}

Thanks! 谢谢!

Since my suggestion in the comments turned out to be what you needed, I am adding it as an answer, with more of an explanation. 由于我在评论中的建议被证明是你所需要的,我将其作为答案添加,并提供更多解释。

When you have a logging application which can not be told to close its logfile (usually via SIGHUP), you can use the 'copytruncate' option in your logrotate.conf. 当您有一个无法告知关闭其日志文件的日志记录应用程序时(通常通过SIGHUP),您可以在logrotate.conf中使用'copytruncate'选项。

Here is the description from the man page: 以下是手册页中的说明:

  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. 

Source: http://linuxcommand.org/man_pages/logrotate8.html 资料来源: http//linuxcommand.org/man_pages/logrotate8.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM