【问题标题】:Logging stdin and stdout记录标准输入和标准输出
【发布时间】:2019-04-08 12:19:50
【问题描述】:

是否有(理想情况下简单而优雅的)记录stdinstdout 的方法?

注意,我确实打算重定向流。我希望标准流保持与其他软件通信的功能,同时将所有进程间通信写入某个文件。

【问题讨论】:

  • 使用tee 应该相当简单。
  • 只需将收到的输入写入文件,以及写入的输出?是的,这可能是代码的一些重复,但它会让您更轻松地根据需要格式化日志记录,或者有一天可以使用一个不错的现有日志记录框架。
  • 否则,您可能需要浏览此处右侧列中列出的“相关”问题列表。
  • @PaulR 事实上,我最初是在寻找 C++ 中的解决方案,但我的 'tee' 可能工作得很好!
  • @PaulR using 'tee' 是我找到的最合理的解决方案,所以如果您(或其他任何人)愿意从中做出回答,我会接受!

标签: c++ io stdout stdin


【解决方案1】:

选项 1:

作为@PaulR suggests,您可以使用 tee 等外部进程(在 Linux/Mac/Unix 上),或编写自己的进程以循环读取 stdin 并写入 stdout 和另一个文件。

选项 2:

多年前,我使用std::basic_ios::rdbufstd::cout 完成了此操作。只需定义一个类(参见std::filebufstd::streambuf):

class tee_buf : public std::filebuf {
   public:
     // Not an owing pointer
     tee_buf(std::streambuf * other_stream) 
        : m_other_stream(other_stream) {}
     void swap( tee_buf& rhs );
     // No need to override open/close since we need to manage only the file.
     // The open/close calls don't touch the other_stream.
   protected:
     int_type overflow(int_type c = traits_type::eof()) override;

     // The parent calls this->overflow(), but then still need to call
     // m_other_stream->sync(). This is problematic since m_other_stream
     // gets flushed twice.
     int sync() override;

     pos_type seekoff( off_type off,
                      std::ios_base::seekdir dir,
                      std::ios_base::openmode which) override {
        return pos_type(off_type(-1)); // ???
     }
     pos_type seekpos( pos_type sp,
                      std::ios_base::openmode which) override {
        return pos_type(off_type(-1)); // ???
     }
     ....

这对于密集的 IO 来说更有效,因为它避免了中间人。但在大多数情况下,三通解决方案更简单、更可取。如果性能是一个问题(在大多数情况下不是),那么可以让两个流缓冲区共享一个内存缓冲区。也可以使用异步 IO 并行写入两个流。

内存泄漏的用法:

std::cout.rdbuf(new tee_buf(std::cout.rdbuf());

使用无内存泄漏:

编写一个 RAII 类以包含 tee_buf,以保存原始并设置新的 std::cout.rdbuf()。销毁后恢复std::cout.rdbuf() 的状态。创建此类的单个实例,它将在其构造和销毁时完成脏活。

至于 C 风格 stdout:我不相信有办法覆盖它的行为。最多可以使用缓冲存储器,但这还不足以获得所需的功能。对于stdout,唯一能做的就是使用类似tee 的解决方案。

【讨论】:

  • 感谢您的回答!选项 2 更符合我原本打算做的事情;但现在我确实相信,在我的应用程序上下文中,选项一更优雅。但是,这并不会影响您的回答对其他读者的有用性!
【解决方案2】:

使用tee 应该相当简单。这将允许您维护任何现有的重定向,同时还将标准输入/标准输出发送到其他地方(在您的情况下发送到文件)。这也避免了对现有代码进行任何修改。

【讨论】: