16 void Write(
const char* data, std::streamsize size)
18 std::lock_guard<std::mutex> lock(m_mutex);
19 if (m_state == State::Buffering)
20 m_pending.append(data,
static_cast<std::size_t
>(size));
21 else if (m_state == State::Open)
22 m_file.write(data, size);
27 std::lock_guard<std::mutex> lock(m_mutex);
28 if (m_state != State::Open)
return 0;
30 return m_file.good() ? 0 : -1;
33 void Open(
const std::string& path)
35 std::lock_guard<std::mutex> lock(m_mutex);
36 m_file.open(path, std::ios::out | std::ios::trunc);
37 if (!m_file.is_open())
38 throw std::runtime_error(
"Could not open output log " + path);
40 m_state = State::Open;
43 static_cast<std::streamsize
>(m_pending.size()));
50 std::lock_guard<std::mutex> lock(m_mutex);
52 m_state = State::Disabled;
57 std::lock_guard<std::mutex> lock(m_mutex);
64 m_state = State::Disabled;
77 std::string m_pending;
78 State m_state = State::Buffering;
82 :
public std::streambuf
85 TeeBuffer(std::streambuf* terminal, LogSink& log)
86 : m_terminal(terminal), m_log(log)
91 int_type overflow(int_type character)
override
93 if (traits_type::eq_int_type(character, traits_type::eof()))
94 return traits_type::not_eof(character);
96 const char value = traits_type::to_char_type(character);
97 if (traits_type::eq_int_type(
98 m_terminal->sputc(value), traits_type::eof()))
99 return traits_type::eof();
100 m_log.Write(&value, 1);
104 std::streamsize xsputn(
105 const char* data, std::streamsize size)
override
107 const std::streamsize written = m_terminal->sputn(data, size);
108 m_log.Write(data, written);
114 const int terminal_status = m_terminal->pubsync();
115 const int log_status = m_log.Sync();
116 return terminal_status == 0 && log_status == 0 ? 0 : -1;
120 std::streambuf* m_terminal;
125std::streambuf* terminal_stdout = std::cout.rdbuf();
126std::streambuf* terminal_stderr = std::cerr.rdbuf();
127std::streambuf* terminal_stdlog = std::clog.rdbuf();
128TeeBuffer stdout_buffer(terminal_stdout, log_sink);
129TeeBuffer stderr_buffer(terminal_stderr, log_sink);
130TeeBuffer stdlog_buffer(terminal_stdlog, log_sink);
140 if (initialized)
return;
141 std::cout.rdbuf(&stdout_buffer);
142 std::cerr.rdbuf(&stderr_buffer);
143 std::clog.rdbuf(&stdlog_buffer);
147void Open(
const std::string& path)
159 if (!initialized)
return;
164 std::cout.rdbuf(terminal_stdout);
165 std::cerr.rdbuf(terminal_stderr);
166 std::clog.rdbuf(terminal_stdlog);
void Initialize()
Route stdout and stderr through the terminal/file tee.
void Finalize()
Flush the log and restore the original terminal stream buffers.
void DisableFile()
Stop retaining output on ranks that do not own the log file.
void Open(const std::string &path)
Open the rank-zero log after the output directory has been created.