Linux 非阻塞 fifo(按需日志记录) [英] Linux non-blocking fifo (on demand logging)

查看:25
本文介绍了Linux 非阻塞 fifo(按需日志记录)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I like to log a programs output 'on demand'. Eg. the output is logged to the terminal, but another process can hook on the current output at any time.

经典的方法是:

myprogram 2>&1 | tee /tmp/mylog

和按需

tail /tmp/mylog

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

However, this would create a ever growing log file even if not used until the drive runs out of space. So my attempt was:

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

和按需

cat /tmp/mylog

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

Now I can read /tmp/mylog at any time. However, any output blocks the program until the /tmp/mylog is read. I like the fifo to flush any incoming data not read back. How to do that?

推荐答案

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

Inspired by your question I've written a simple program that will let you do this:

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

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

It behaves similarly to tee but clones the stdin to stdout and to a named pipe (a requirement for now) without blocking. This means that if you want to log this way it may happen that you're gonna lose your log data, but I guess it's acceptable in your scenario. The trick is to block SIGPIPE signal and to ignore error on writing to a broken fifo. This sample may be optimized in various ways of course, but so far, it does the job I guess.

/* 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:
 someprog 2>&1 | %s FIFO
 FIFO - path to a"
            " named pipe, required argument
", 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!
", 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);
}

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

You can compile it with this standard command:

$ gcc ftee.c -o ftee

您可以通过运行例如:

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

$ cat/tmp/mylog

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

Also note - this is no multiplexer. You can only have one process doing $ cat /tmp/mylog at a time.

这篇关于Linux 非阻塞 fifo(按需日志记录)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆