Linux 非阻塞 fifo(按需日志记录)

标签 linux bash logging fifo

我喜欢“按需”记录程序输出。例如。输出记录到终端,但另一个进程可以随时挂接当前输出。

经典的方法是:

myprogram 2>&1 | tee /tmp/mylog

随需应变

tail /tmp/mylog

但是,即使在驱动器空间用完之前不使用,这也会创建一个不断增长的日志文件。所以我的尝试是:

mkfifo /tmp/mylog
myprogram 2>&1 | tee /tmp/mylog

随需应变

cat /tmp/mylog

现在我可以随时阅读/tmp/mylog。但是,在读取/tmp/mylog 之前,任何输出都会阻塞程序。我喜欢先进先出刷新任何未读回的传入数据。该怎么做?

最佳答案

受您的问题启发,我编写了一个简单的程序,可以让您这样做:

$ myprogram 2>&1 | ftee/tmp/mylog

它的行为与 tee 类似,但将标准输入克隆到标准输出和命名管道(现在是必需的)而不会阻塞。这意味着如果您想以这种方式记录,您可能会丢失日志数据,但我想这在您的场景中是可以接受的。 诀窍是阻止 SIGPIPE 信号并忽略写入损坏的 fifo 时的错误。 这个示例当然可以通过各种方式进行优化,但到目前为止,它确实做到了我猜是工作。

/* ftee - clone stdin to stdout and to a named pipe 
(c) racic@stackoverflow
WTFPL Licence */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int readfd, writefd;
    struct stat status;
    char *fifonam;
    char buffer[BUFSIZ];
    ssize_t bytes;
    
    signal(SIGPIPE, SIG_IGN);

    if(2!=argc)
    {
        printf("Usage:\n someprog 2>&1 | %s FIFO\n FIFO - path to a"
            " named pipe, required argument\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    fifonam = argv[1];

    readfd = open(fifonam, O_RDONLY | O_NONBLOCK);
    if(-1==readfd)
    {
        perror("ftee: readfd: open()");
        exit(EXIT_FAILURE);
    }

    if(-1==fstat(readfd, &status))
    {
        perror("ftee: fstat");
        close(readfd);
        exit(EXIT_FAILURE);
    }

    if(!S_ISFIFO(status.st_mode))
    {
        printf("ftee: %s in not a fifo!\n", fifonam);
        close(readfd);
        exit(EXIT_FAILURE);
    }

    writefd = open(fifonam, O_WRONLY | O_NONBLOCK);
    if(-1==writefd)
    {
        perror("ftee: writefd: open()");
        close(readfd);
        exit(EXIT_FAILURE);
    }

    close(readfd);

    while(1)
    {
        bytes = read(STDIN_FILENO, buffer, sizeof(buffer));
        if (bytes < 0 && errno == EINTR)
            continue;
        if (bytes <= 0)
            break;

        bytes = write(STDOUT_FILENO, buffer, bytes);
        if(-1==bytes)
            perror("ftee: writing to stdout");
        bytes = write(writefd, buffer, bytes);
        if(-1==bytes);//Ignoring the errors
    }
    close(writefd); 
    return(0);
}

你可以用这个标准命令编译它:

$ gcc ftee.c -o ftee

您可以通过运行例如:

快速验证它

$ ping www.google.com | ftee/tmp/mylog

$ cat/tmp/mylog

另请注意 - 这不是多路复用器。一次只能让一个进程执行 $ cat/tmp/mylog

关于Linux 非阻塞 fifo(按需日志记录),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7360473/

相关文章:

linux - 带有变量的 tcl sed

linux - 带参数的 Bash 函数

bash - fish shell 中的全局匹配(通配符)不匹配 bash 行为

java - 令人困惑的日志错误 TimeBasedArchiveRemover$ArhiveRemoverRunnable

logging - 在 Gorilla Handler 中记录线程 ID

c - 使用 setsockopt;当套接字从另一端关闭时,read 返回 0 而不是 -1

linux - Unix 中的包装函数参数是否有任何限制?

bash - 并行执行多个作业时指定 SLURM 资源

linux - shell 脚本 - 将所有数据从 stdout 重定向到/dev/null

.net - NLog:记录在 IIS 中的 WCF 应用程序中调用该应用程序的用户