Belle II Software  release-05-02-19
IOIntercept.h
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2017 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Martin Ritter *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #pragma once
12 
13 #include <iostream>
14 #include <string>
15 #include <framework/logging/LogConfig.h>
16 
17 namespace Belle2 {
23  namespace IOIntercept {
25  class StreamInterceptor {
26  public:
34  StreamInterceptor(std::ostream& stream, FILE* fileObject);
37 
40  bool start()
41  {
42  // only start if we are not already running
44  return m_capturing;
45  }
48  bool finish()
49  {
50  if (!m_capturing) return false;
51  m_capturing = false;
52  return replaceFD(m_savedFD);
53  }
54  protected:
56  void setReplacementFD(int fd) { m_replacementFD = fd; }
61  static void readFD(int fd, std::string& out);
65  bool replaceFD(int fileDescriptor);
67  std::ostream& m_stream;
69  FILE* m_fileObject;
71  int m_savedFD{ -1};
73  int m_replacementFD{ -1};
75  bool m_capturing{false};
76  };
77 
79  class KeepStream {
80  public:
82  KeepStream(std::ostream&, FILE*) {}
84  bool start() const { return true; }
86  bool finish() const { return true; }
87  };
88 
91  public:
93  DiscardStream(std::ostream& stream, FILE* fileObject);
94  };
95 
105  class CaptureStream: public StreamInterceptor {
106  public:
108  CaptureStream(std::ostream& stream, FILE* fileObject);
110  ~CaptureStream();
112  const std::string& getOutput() const { return m_outputStr; }
114  bool start();
116  bool finish();
117  private:
119  int m_pipeReadFD{ -1};
121  std::string m_outputStr;
123  friend class CaptureStreamAbortHandler;
124  };
125 
126 
152  template<class STDOUT, class STDERR>
153  class InterceptOutput {
154  public:
157  bool start() { return m_stdout.start() && m_stderr.start(); }
160  bool finish() { return m_stdout.finish() && m_stderr.finish(); }
162  const std::string& getStdOut() const
163  {
164  static_assert(std::is_same<STDOUT, CaptureStream>::value, "Only valid if stdout is captured using CaptureStream");
165  return m_stdout.getOutput();
166  }
168  const std::string& getStdErr() const
169  {
170  static_assert(std::is_same<STDERR, CaptureStream>::value, "Only valid if stderr is captured using CaptureStream");
171  return m_stderr.getOutput();
172  }
173 
174  private:
176  STDOUT m_stdout{std::cout, stdout};
178  STDERR m_stderr{std::cerr, stderr};
179  };
180 
182  using CaptureStdOutStdErr = InterceptOutput<CaptureStream, CaptureStream>;
197 
229  public:
237  OutputToLogMessages(const std::string& name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel,
238  int stdoutDebugLevel, int stderrDebugLevel):
239  m_name(name), m_indent(name + ": "), m_stdoutLevel(stdoutLevel), m_stderrLevel(stderrLevel),
240  m_stdoutDebugLevel(stdoutDebugLevel), m_stderrDebugLevel(stderrDebugLevel)
241  {}
248  OutputToLogMessages(const std::string& name, LogConfig::ELogLevel stdoutLevel, LogConfig::ELogLevel stderrLevel):
249  OutputToLogMessages(name, stdoutLevel, stderrLevel, 100, 100)
250  {}
254  explicit OutputToLogMessages(const std::string& name): OutputToLogMessages(name, LogConfig::c_Info, LogConfig::c_Error)
255  {}
259  void setIndent(const std::string& indent) { m_indent = indent; }
261  bool finish();
262  private:
264  const std::string m_name;
266  std::string m_indent;
275  };
276 
303  template<class T> class InterceptorScopeGuard {
304  public:
309  explicit InterceptorScopeGuard(T& interceptor): m_interceptor(&interceptor)
310  {
311  m_interceptor->start();
312  }
315  {
316  b.m_interceptor = nullptr;
317  }
324  {
325  if (m_interceptor) m_interceptor->finish();
326  }
327  private:
329  T* m_interceptor;
330  };
331 
347  template<class T> InterceptorScopeGuard<T> start_intercept(T& interceptor)
348  {
349  return InterceptorScopeGuard<T> {interceptor};
350  }
351  }
353 }
Belle2::IOIntercept::InterceptorScopeGuard::m_interceptor
T * m_interceptor
pointer to the interceptor we guard
Definition: IOIntercept.h:337
Belle2::IOIntercept::StreamInterceptor::m_savedFD
int m_savedFD
Saved file descriptor: a duplicate of the file descriptor of m_fileObject.
Definition: IOIntercept.h:79
Belle2::IOIntercept::StreamInterceptor::start
bool start()
start intercepting the stream.
Definition: IOIntercept.h:48
Belle2::IOIntercept::StreamInterceptor::~StreamInterceptor
~StreamInterceptor()
close file descriptors
Definition: IOIntercept.cc:105
Belle2::IOIntercept::DiscardStream::DiscardStream
DiscardStream(std::ostream &stream, FILE *fileObject)
Create StreamInterceptor which will redirect to /dev/null.
Definition: IOIntercept.cc:155
Belle2::IOIntercept::OutputToLogMessages::setIndent
void setIndent(const std::string &indent)
Set the indent for each line of the output, default is the supplied name + ": "
Definition: IOIntercept.h:267
Belle2::IOIntercept::KeepStream::start
bool start() const
doing nothing always succeds
Definition: IOIntercept.h:92
Belle2::IOIntercept::CaptureStream::~CaptureStream
~CaptureStream()
Close file descriptors.
Definition: IOIntercept.cc:177
Belle2::IOIntercept::OutputToLogMessages::m_stdoutDebugLevel
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:280
Belle2::IOIntercept::InterceptorScopeGuard::InterceptorScopeGuard
InterceptorScopeGuard(T &interceptor)
Construct a new instance for a given interceptor object and start intercepting io.
Definition: IOIntercept.h:317
Belle2::IOIntercept::StreamInterceptor::m_fileObject
FILE * m_fileObject
File object of the file we want to replace, needed to obtain file descriptor and to flush.
Definition: IOIntercept.h:77
Belle2::IOIntercept::OutputToLogMessages::m_stderrDebugLevel
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:282
Belle2::IOIntercept::InterceptOutput::m_stderr
STDERR m_stderr
StreamInterceptor for stderr.
Definition: IOIntercept.h:186
Belle2::IOIntercept::StreamInterceptor::setReplacementFD
void setReplacementFD(int fd)
set the replacement file descriptor, should be called in the constructor of derived classes
Definition: IOIntercept.h:64
Belle2::IOIntercept::DiscardStream
Simple class to just discard anything written to stream by redirecting it to /dev/null.
Definition: IOIntercept.h:98
Belle2::IOIntercept::KeepStream::KeepStream
KeepStream(std::ostream &, FILE *)
This class is basically empty so the constructor does nothing.
Definition: IOIntercept.h:90
Belle2::IOIntercept::OutputToLogMessages::m_stdoutLevel
LogConfig::ELogLevel m_stdoutLevel
severity of the log message to be emitted for output on stdout
Definition: IOIntercept.h:276
Belle2::IOIntercept::CaptureStream::finish
bool finish()
Restore the stream and get the output from the pipe.
Definition: IOIntercept.cc:195
Belle2::IOIntercept::OutputToLogMessages::finish
bool finish()
Finish the capture and emit the message if output has appeard on stdout or stderr.
Definition: IOIntercept.cc:245
Belle2::LogConfig::c_Info
@ c_Info
Info: for informational messages, e.g.
Definition: LogConfig.h:37
Belle2::IOIntercept::OutputToLogMessages::OutputToLogMessages
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:245
Belle2::IOIntercept::CaptureStream::m_outputStr
std::string m_outputStr
string with the output, only filled after finish()
Definition: IOIntercept.h:129
Belle2::IOIntercept::OutputToLogMessages::m_indent
std::string m_indent
Identation to add to the beginning of each line of output.
Definition: IOIntercept.h:274
Belle2::LogConfig::ELogLevel
ELogLevel
Definition of the supported log levels.
Definition: LogConfig.h:36
Belle2::IOIntercept::CaptureStream::CaptureStream
CaptureStream(std::ostream &stream, FILE *fileObject)
Create a StreamInterceptor which writes into a pipe.
Definition: IOIntercept.cc:166
Belle2::IOIntercept::InterceptOutput::finish
bool finish()
Finish intercepting the output.
Definition: IOIntercept.h:168
Belle2::IOIntercept::StreamInterceptor::m_replacementFD
int m_replacementFD
Replacement file descriptor to be used while capturing.
Definition: IOIntercept.h:81
Belle2::IOIntercept::InterceptOutput::getStdOut
const std::string & getStdOut() const
Return the captured stdout output if any.
Definition: IOIntercept.h:170
Belle2::IOIntercept::InterceptOutput::m_stdout
STDOUT m_stdout
StreamInterceptor for stdout.
Definition: IOIntercept.h:184
Belle2::IOIntercept::CaptureStream
Class to capture anything written to stream into a string.
Definition: IOIntercept.h:113
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::IOIntercept::StreamInterceptor::finish
bool finish()
stop intercepting the stream.
Definition: IOIntercept.h:56
Belle2::IOIntercept::start_intercept
InterceptorScopeGuard< T > start_intercept(T &interceptor)
Convenience wrapper to simplify use of InterceptorScopeGuard<T>.
Definition: IOIntercept.h:355
Belle2::LogConfig::c_Error
@ c_Error
Error: for things that went wrong and have to be fixed.
Definition: LogConfig.h:40
Belle2::IOIntercept::InterceptOutput::start
bool start()
Start intercepting the output.
Definition: IOIntercept.h:165
Belle2::IOIntercept::KeepStream
Dummy class which keeps the stream unmodified.
Definition: IOIntercept.h:87
Belle2::IOIntercept::OutputToLogMessages::m_stderrLevel
LogConfig::ELogLevel m_stderrLevel
severity of the log message to be emitted for output on stderr
Definition: IOIntercept.h:278
Belle2::IOIntercept::InterceptorScopeGuard
Simple RAII guard for output interceptor.
Definition: IOIntercept.h:311
Belle2::IOIntercept::InterceptorScopeGuard::operator=
InterceptorScopeGuard & operator=(const InterceptorScopeGuard &)=delete
Also no assignment.
Belle2::IOIntercept::OutputToLogMessages::~OutputToLogMessages
~OutputToLogMessages()
Destructor to make sure that output is converted to messages on destruction.
Definition: IOIntercept.h:265
Belle2::IOIntercept::InterceptOutput::getStdErr
const std::string & getStdErr() const
Return the captured stderr output if any.
Definition: IOIntercept.h:176
Belle2::IOIntercept::StreamInterceptor
Base class with all necessary features to intercept output to a file descriptor.
Definition: IOIntercept.h:33
Belle2::IOIntercept::OutputToLogMessages::m_name
const std::string m_name
Name of the output producing tool/library.
Definition: IOIntercept.h:272
Belle2::IOIntercept::CaptureStream::getOutput
const std::string & getOutput() const
Get the output, only set after finish()
Definition: IOIntercept.h:120
Belle2::IOIntercept::OutputToLogMessages
Capture stdout and stderr and convert into log messages.
Definition: IOIntercept.h:236
Belle2::IOIntercept::StreamInterceptor::m_capturing
bool m_capturing
Check whether we are already capturing.
Definition: IOIntercept.h:83
Belle2::IOIntercept::KeepStream::finish
bool finish() const
doing nothing always succeds
Definition: IOIntercept.h:94
Belle2::IOIntercept::CaptureStream::m_pipeReadFD
int m_pipeReadFD
file descriptor of the read end of the pipe
Definition: IOIntercept.h:127
Belle2::IOIntercept::StreamInterceptor::m_stream
std::ostream & m_stream
C++ stream object, only needed to flush before replacement.
Definition: IOIntercept.h:75
Belle2::IOIntercept::CaptureStream::start
bool start()
Start intercepting the output.
Definition: IOIntercept.cc:186
Belle2::IOIntercept::InterceptOutput
Class to intercept stdout and stderr and either capture, discard or keep them unmodified depending on...
Definition: IOIntercept.h:161
Belle2::IOIntercept::CaptureStream::CaptureStreamAbortHandler
friend class CaptureStreamAbortHandler
allow handling of SIGABRT
Definition: IOIntercept.h:131
Belle2::IOIntercept::StreamInterceptor::replaceFD
bool replaceFD(int fileDescriptor)
Replace the file descriptor of m_fileObject with the one passed.
Definition: IOIntercept.cc:130
Belle2::IOIntercept::CaptureStdOutStdErr
InterceptOutput< CaptureStream, CaptureStream > CaptureStdOutStdErr
Capture both stdout and stderr as strings.
Definition: IOIntercept.h:190
Belle2::IOIntercept::StreamInterceptor::readFD
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:112
Belle2::IOIntercept::StreamInterceptor::StreamInterceptor
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:98
Belle2::IOIntercept::InterceptorScopeGuard::~InterceptorScopeGuard
~InterceptorScopeGuard()
Finish interception on cleanup.
Definition: IOIntercept.h:331