9#include <framework/utilities/IOIntercept.h> 
   10#include <framework/logging/Logger.h> 
   17#include <boost/algorithm/string.hpp> 
   57      if (result == SIG_ERR) B2FATAL(
"Cannot register abort handler");
 
 
   60    static void handle(
int signal);
 
 
   69    std::set<CaptureStream*> objects;
 
   75      close(stream->m_replacementFD);
 
   77      if (stream->finish()) {
 
   78        const std::string& out = stream->getOutput();
 
   80        if (out.size()) write(stream->m_savedFD, out.c_str(), out.size());
 
   84    write(STDERR_FILENO, 
"abort() called, exiting\n", 24);
 
   85    std::_Exit(EXIT_FAILURE);
 
 
   92      B2ERROR(
"Error duplicating file descriptor: " << std::strerror(errno));
 
 
  107    static std::unique_ptr<char[]> buffer(
new char[1024]);
 
  110      ssize_t size = read(fd, buffer.get(), 1024);
 
  113        if (size < 0 && errno == EINTR)  
continue;
 
  116      out.append(buffer.get(), 
static_cast<size_t>(size));
 
 
  123    if (fileDescriptor < 0) 
return false;
 
  132      B2ERROR(
"Error obtaining file descriptor: " << std::strerror(errno));
 
  135    while (dup2(fileDescriptor, currentFD) < 0) {
 
  136      if (errno != EINTR && errno != EBUSY) {
 
  137        B2ERROR(
"Error in dup2(), cannot replace file descriptor: " << std::strerror(errno));
 
 
  147    int devNull = open(
"/dev/null", O_WRONLY);
 
  150      B2ERROR(
"Cannot open /dev/null: " << std::strerror(errno));
 
 
  159    if (pipe2(pipeFD, O_NONBLOCK) < 0) {
 
  160      B2ERROR(
"Error creating pipe: " << std::strerror(errno));
 
 
  208    void sendLogMessage(
LogConfig::ELogLevel logLevel, 
int debugLevel, 
const std::string& name, 
const std::string& indent,
 
  214      boost::algorithm::trim_right(message);
 
  216      while (!message.empty()) {
 
  217        std::string new_message = boost::algorithm::trim_left_copy_if(message, boost::algorithm::is_any_of(
" \t\r"));
 
  218        if (new_message.empty()) {
 
  219          message = new_message;
 
  220        } 
else if (new_message[0] == 
'\n') {
 
  221          message = new_message.substr(1, std::string::npos);
 
  228      if (message.empty()) 
return;
 
  230      boost::algorithm::replace_all(message, 
"\n", 
"\n" + indent);
 
  232      B2LOG(logLevel, debugLevel, 
"Output from " << name << 
":\n" << indent << message);
 
CaptureStreamAbortHandler()
Register handler.
void removeObject(CaptureStream *obj)
Remove a CaptureStream object to no longer guard against SIGABRT.
void addObject(CaptureStream *obj)
Add a CaptureStream object to guard against SIGABRT.
static CaptureStreamAbortHandler & getInstance()
Return the singleton instance.
CaptureStreamAbortHandler(CaptureStreamAbortHandler &&)=delete
Singleton, no move construction.
static void handle(int signal)
signal handler: print all pending redirection buffers and exit
std::set< CaptureStream * > m_objects
list of all active stream redirections
CaptureStreamAbortHandler & operator=(const CaptureStreamAbortHandler &)=delete
Singleton, no assignment.
CaptureStreamAbortHandler(const CaptureStreamAbortHandler &)=delete
Singleton, no copy construction.
Class to capture anything written to stream into a string.
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()
int m_pipeReadFD
file descriptor of the read end of the pipe
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.
const std::string & getStdOut() const
const std::string & getStdErr() const
LogConfig::ELogLevel m_stderrLevel
severity of the log message to be emitted for output on 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
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.
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.
void setReplacementFD(int fd)
set the replacement file descriptor, should be called in the constructor of derived classes
bool start()
start intercepting the stream.
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.
int m_savedFD
Saved file descriptor: a duplicate of the file descriptor of m_fileObject.
bool finish()
stop intercepting the stream.
ELogLevel
Definition of the supported log levels.
static LogSystem & Instance()
Static method to get a reference to the LogSystem instance.
Encapsulate all classes needed to intercept stdout and stderr.