Belle II Software  release-08-01-10
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 
15 namespace 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  }
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;
67  FILE* m_fileObject;
69  int m_savedFD{ -1};
71  int m_replacementFD{ -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);
108  ~CaptureStream();
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  }
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  {}
246  OutputToLogMessages(const std::string& name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel):
247  OutputToLogMessages(name, stdoutLevel, stderrLevel, 100, 100)
248  {}
252  explicit OutputToLogMessages(const std::string& name): OutputToLogMessages(name, LogConfig::c_Info, LogConfig::c_Error)
253  {}
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  }
313  {
314  b.m_interceptor = nullptr;
315  }
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  }
351 }
Small class to handle std::abort() calls by external libraries.
Definition: IOIntercept.cc:34
Class to capture anything written to stream into a string.
Definition: IOIntercept.h:103
CaptureStream(std::ostream &stream, FILE *fileObject)
Create a StreamInterceptor which writes into a pipe.
Definition: IOIntercept.cc:156
std::string m_outputStr
string with the output, only filled after finish()
Definition: IOIntercept.h:119
const std::string & getOutput() const
Get the output, only set after finish()
Definition: IOIntercept.h:110
int m_pipeReadFD
file descriptor of the read end of the pipe
Definition: IOIntercept.h:117
bool start()
Start intercepting the output.
Definition: IOIntercept.cc:176
~CaptureStream()
Close file descriptors.
Definition: IOIntercept.cc:167
bool finish()
Restore the stream and get the output from the pipe.
Definition: IOIntercept.cc:185
Simple class to just discard anything written to stream by redirecting it to /dev/null.
Definition: IOIntercept.h:88
DiscardStream(std::ostream &stream, FILE *fileObject)
Create StreamInterceptor which will redirect to /dev/null.
Definition: IOIntercept.cc:145
Class to intercept stdout and stderr and either capture, discard or keep them unmodified depending on...
Definition: IOIntercept.h:151
STDOUT m_stdout
StreamInterceptor for stdout.
Definition: IOIntercept.h:174
STDERR m_stderr
StreamInterceptor for stderr.
Definition: IOIntercept.h:176
const std::string & getStdErr() const
Return the captured stderr output if any.
Definition: IOIntercept.h:166
const std::string & getStdOut() const
Return the captured stdout output if any.
Definition: IOIntercept.h:160
bool start()
Start intercepting the output.
Definition: IOIntercept.h:155
bool finish()
Finish intercepting the output.
Definition: IOIntercept.h:158
Simple RAII guard for output interceptor.
Definition: IOIntercept.h:301
InterceptorScopeGuard & operator=(const InterceptorScopeGuard &)=delete
Also no assignment.
InterceptorScopeGuard(InterceptorScopeGuard< T > &&b)
Move constructor which will take over the interception state.
Definition: IOIntercept.h:312
~InterceptorScopeGuard()
Finish interception on cleanup.
Definition: IOIntercept.h:321
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.
Definition: IOIntercept.h:307
T * m_interceptor
pointer to the interceptor we guard
Definition: IOIntercept.h:327
Dummy class which keeps the stream unmodified.
Definition: IOIntercept.h:77
KeepStream(std::ostream &, FILE *)
This class is basically empty so the constructor does nothing.
Definition: IOIntercept.h:80
bool start() const
doing nothing always succeds
Definition: IOIntercept.h:82
bool finish() const
doing nothing always succeds
Definition: IOIntercept.h:84
Capture stdout and stderr and convert into log messages.
Definition: IOIntercept.h:226
OutputToLogMessages(const std::string &name)
Simple constructor which uses c_Info for output on stdout and c_Error for output on stderr.
Definition: IOIntercept.h:252
LogConfig::ELogLevel m_stderrLevel
severity of the log message to be emitted for output on stderr
Definition: IOIntercept.h:268
OutputToLogMessages(const std::string &name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel)
Constructor to choose the log levels both stdout and stderr.
Definition: IOIntercept.h:246
const std::string m_name
Name of the output producing tool/library.
Definition: IOIntercept.h:262
int m_stderrDebugLevel
debug level for the log message to be emitted for output on stderr if m_stderrLevel is c_Debug
Definition: IOIntercept.h:272
void setIndent(const std::string &indent)
Set the indent for each line of the output, default is the supplied name + ": "
Definition: IOIntercept.h:257
~OutputToLogMessages()
Destructor to make sure that output is converted to messages on destruction.
Definition: IOIntercept.h:255
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.
Definition: IOIntercept.h:235
LogConfig::ELogLevel m_stdoutLevel
severity of the log message to be emitted for output on stdout
Definition: IOIntercept.h:266
bool finish()
Finish the capture and emit the message if output has appeard on stdout or stderr.
Definition: IOIntercept.cc:236
int m_stdoutDebugLevel
debug level for the log message to be emitted for output on stdout if m_stdoutLevel is c_Debug
Definition: IOIntercept.h:270
std::string m_indent
Identation to add to the beginning of each line of output.
Definition: IOIntercept.h:264
Base class with all necessary features to intercept output to a file descriptor.
Definition: IOIntercept.h:23
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.
Definition: IOIntercept.cc:102
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.
Definition: IOIntercept.cc:120
~StreamInterceptor()
close file descriptors
Definition: IOIntercept.cc:95
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...
Definition: IOIntercept.cc:88
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
InterceptorScopeGuard< T > start_intercept(T &interceptor)
Convenience wrapper to simplify use of InterceptorScopeGuard<T>.
Definition: IOIntercept.h:345
Abstract base class for different kinds of events.