Belle II Software development
IOIntercept.h
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#pragma once
10
11#include <iostream>
12#include <string>
13#include <framework/logging/LogConfig.h>
14
15namespace Belle2 {
21 namespace IOIntercept {
24 public:
32 StreamInterceptor(std::ostream& stream, FILE* fileObject);
35
38 bool start()
39 {
40 // only start if we are not already running
42 return m_capturing;
43 }
44
46 bool finish()
47 {
48 if (!m_capturing) return false;
49 m_capturing = false;
50 return replaceFD(m_savedFD);
51 }
52 protected:
54 void setReplacementFD(int fd) { m_replacementFD = fd; }
59 static void readFD(int fd, std::string& out);
63 bool replaceFD(int fileDescriptor);
65 std::ostream& m_stream;
69 int m_savedFD{ -1};
73 bool m_capturing{false};
74 };
75
77 class KeepStream {
78 public:
80 KeepStream(std::ostream&, FILE*) {}
82 bool start() const { return true; }
84 bool finish() const { return true; }
85 };
86
89 public:
91 DiscardStream(std::ostream& stream, FILE* fileObject);
92 };
93
104 public:
106 CaptureStream(std::ostream& stream, FILE* fileObject);
110 const std::string& getOutput() const { return m_outputStr; }
112 bool start();
114 bool finish();
115 private:
117 int m_pipeReadFD{ -1};
119 std::string m_outputStr;
122 };
123
124
150 template<class STDOUT, class STDERR>
152 public:
155 bool start() { return m_stdout.start() && m_stderr.start(); }
158 bool finish() { return m_stdout.finish() && m_stderr.finish(); }
160 const std::string& getStdOut() const
161 {
162 static_assert(std::is_same<STDOUT, CaptureStream>::value, "Only valid if stdout is captured using CaptureStream");
163 return m_stdout.getOutput();
164 }
165
166 const std::string& getStdErr() const
167 {
168 static_assert(std::is_same<STDERR, CaptureStream>::value, "Only valid if stderr is captured using CaptureStream");
169 return m_stderr.getOutput();
170 }
171
172 private:
174 STDOUT m_stdout{std::cout, stdout};
176 STDERR m_stderr{std::cerr, stderr};
177 };
178
195
227 public:
235 OutputToLogMessages(const std::string& name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel,
236 int stdoutDebugLevel, int stderrDebugLevel):
237 m_name(name), m_indent(name + ": "), m_stdoutLevel(stdoutLevel), m_stderrLevel(stderrLevel),
238 m_stdoutDebugLevel(stdoutDebugLevel), m_stderrDebugLevel(stderrDebugLevel)
239 {}
240
246 OutputToLogMessages(const std::string& name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel):
247 OutputToLogMessages(name, stdoutLevel, stderrLevel, 100, 100)
248 {}
249
252 explicit OutputToLogMessages(const std::string& name): OutputToLogMessages(name, LogConfig::c_Info, LogConfig::c_Error)
253 {}
254
257 void setIndent(const std::string& indent) { m_indent = indent; }
259 bool finish();
260 private:
262 const std::string m_name;
264 std::string m_indent;
273 };
274
301 template<class T> class InterceptorScopeGuard {
302 public:
307 explicit InterceptorScopeGuard(T& interceptor): m_interceptor(&interceptor)
308 {
309 m_interceptor->start();
310 }
311
313 {
314 b.m_interceptor = nullptr;
315 }
316
322 {
323 if (m_interceptor) m_interceptor->finish();
324 }
325 private:
328 };
329
345 template<class T> InterceptorScopeGuard<T> start_intercept(T& interceptor)
346 {
347 return InterceptorScopeGuard<T> {interceptor};
348 }
349 }
350
351}
CaptureStream(std::ostream &stream, FILE *fileObject)
Create a StreamInterceptor which writes into a pipe.
std::string m_outputStr
string with the output, only filled after finish()
const std::string & getOutput() const
Get the output, only set after finish()
int m_pipeReadFD
file descriptor of the read end of the pipe
friend class CaptureStreamAbortHandler
allow handling of SIGABRT
bool start()
Start intercepting the output.
~CaptureStream()
Close file descriptors.
bool finish()
Restore the stream and get the output from the pipe.
DiscardStream(std::ostream &stream, FILE *fileObject)
Create StreamInterceptor which will redirect to /dev/null.
Class to intercept stdout and stderr and either capture, discard or keep them unmodified depending on...
const std::string & getStdOut() const
Return the captured stdout output if any.
bool start()
Start intercepting the output.
bool finish()
Finish intercepting the output.
const std::string & getStdErr() const
Return the captured stderr output if any.
Simple RAII guard for output interceptor.
InterceptorScopeGuard(InterceptorScopeGuard< T > &&b)
Move constructor which will take over the interception state.
~InterceptorScopeGuard()
Finish interception on cleanup.
InterceptorScopeGuard(const InterceptorScopeGuard< T > &)=delete
We don't want copying.
InterceptorScopeGuard(T &interceptor)
Construct a new instance for a given interceptor object and start intercepting io.
InterceptorScopeGuard & operator=(const InterceptorScopeGuard &)=delete
Also no assignment.
T * m_interceptor
pointer to the interceptor we guard
KeepStream(std::ostream &, FILE *)
This class is basically empty so the constructor does nothing.
Definition IOIntercept.h:80
bool start() const
doing nothing always succeeds
Definition IOIntercept.h:82
bool finish() const
doing nothing always succeeds
Definition IOIntercept.h:84
OutputToLogMessages(const std::string &name)
Simple constructor which uses c_Info for output on stdout and c_Error for output on stderr.
LogConfig::ELogLevel m_stderrLevel
severity of the log message to be emitted for output on stderr
OutputToLogMessages(const std::string &name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel)
Constructor to choose the log levels both stdout and stderr.
const std::string m_name
Name of the output producing tool/library.
int m_stderrDebugLevel
debug level for the log message to be emitted for output on stderr if m_stderrLevel is c_Debug
void setIndent(const std::string &indent)
Set the indent for each line of the output, default is the supplied name + ": "
~OutputToLogMessages()
Destructor to make sure that output is converted to messages on destruction.
OutputToLogMessages(const std::string &name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel, int stdoutDebugLevel, int stderrDebugLevel)
Full constructor to choose the log levels and debug levels for both stdout and stderr.
LogConfig::ELogLevel m_stdoutLevel
severity of the log message to be emitted for output on stdout
bool finish()
Finish the capture and emit the message if output has appeard on stdout or stderr.
int m_stdoutDebugLevel
debug level for the log message to be emitted for output on stdout if m_stdoutLevel is c_Debug
std::string m_indent
Indentation to add to the beginning of each line of output.
static void readFD(int fd, std::string &out)
Read the contents of a file descriptor until there is no more input and place them in out.
std::ostream & m_stream
C++ stream object, only needed to flush before replacement.
Definition IOIntercept.h:65
bool replaceFD(int fileDescriptor)
Replace the file descriptor of m_fileObject with the one passed.
~StreamInterceptor()
close file descriptors
FILE * m_fileObject
File object of the file we want to replace, needed to obtain file descriptor and to flush.
Definition IOIntercept.h:67
void setReplacementFD(int fd)
set the replacement file descriptor, should be called in the constructor of derived classes
Definition IOIntercept.h:54
bool start()
start intercepting the stream.
Definition IOIntercept.h:38
StreamInterceptor(std::ostream &stream, FILE *fileObject)
Construct keeping a reference to the std::ostream and the file descriptor which are associated with t...
int m_replacementFD
Replacement file descriptor to be used while capturing.
Definition IOIntercept.h:71
int m_savedFD
Saved file descriptor: a duplicate of the file descriptor of m_fileObject.
Definition IOIntercept.h:69
bool finish()
stop intercepting the stream.
Definition IOIntercept.h:46
bool m_capturing
Check whether we are already capturing.
Definition IOIntercept.h:73
The LogConfig class.
Definition LogConfig.h:22
ELogLevel
Definition of the supported log levels.
Definition LogConfig.h:26
Encapsulate all classes needed to intercept stdout and stderr.
Definition IOIntercept.h:21
InterceptOutput< DiscardStream, DiscardStream > DiscardStdOutStdErr
Discard both stdout and stderr.
InterceptOutput< CaptureStream, KeepStream > CaptureStdOut
Capture only stdout and don't modify stderr.
InterceptOutput< CaptureStream, DiscardStream > CaptureStdOutDiscardStdErr
Capture stdout and discard stderr.
InterceptorScopeGuard< T > start_intercept(T &interceptor)
Convenience wrapper to simplify use of InterceptorScopeGuard<T>.
InterceptOutput< CaptureStream, CaptureStream > CaptureStdOutStdErr
Capture both stdout and stderr as strings.
InterceptOutput< DiscardStream, KeepStream > DiscardStdOut
Discard only stdout and don't modify stderr.
InterceptOutput< KeepStream, DiscardStream > DiscardStdErr
Discard only stderr and don't modify stdout.
InterceptOutput< DiscardStream, CaptureStream > DiscardStdOutCaptureStdErr
Capture stderr and discard stdout.
InterceptOutput< KeepStream, CaptureStream > CaptureStdErr
Capture only stderr and don't modify stdout.
Abstract base class for different kinds of events.