 |
Belle II Software
release-05-02-19
|
11 #include <framework/utilities/IOIntercept.h>
12 #include <framework/logging/Logger.h>
19 #include <boost/algorithm/string.hpp>
36 class CaptureStreamAbortHandler {
59 if (result == SIG_ERR) B2FATAL(
"Cannot register abort handler");
62 static void handle(
int signal);
71 std::set<CaptureStream*> objects;
77 close(stream->m_replacementFD);
79 if (stream->finish()) {
80 const std::string& out = stream->getOutput();
82 if (out.size()) write(stream->m_savedFD, out.c_str(), out.size());
86 write(STDERR_FILENO,
"abort() called, exiting\n", 24);
87 std::_Exit(EXIT_FAILURE);
91 m_stream(stream), m_fileObject(fileObject), m_savedFD(dup(fileno(m_fileObject)))
94 B2ERROR(
"Error duplicating file descriptor: " << std::strerror(errno));
109 static std::unique_ptr<char[]> buffer(
new char[1024]);
112 ssize_t size = read(fd, buffer.get(), 1024);
115 if (size < 0 && errno == EINTR)
continue;
118 out.append(buffer.get(),
static_cast<size_t>(size));
125 if (fileDescriptor < 0)
return false;
134 B2ERROR(
"Error obtaining file descriptor: " << std::strerror(errno));
137 while (dup2(fileDescriptor, currentFD) < 0) {
138 if (errno != EINTR && errno != EBUSY) {
139 B2ERROR(
"Error in dup2(), cannot replace file descriptor: " << std::strerror(errno));
149 int devNull = open(
"/dev/null", O_WRONLY);
152 B2ERROR(
"Cannot open /dev/null: " << std::strerror(errno));
161 if (pipe2(pipeFD, O_NONBLOCK) < 0) {
162 B2ERROR(
"Error creating pipe: " << std::strerror(errno));
165 m_pipeReadFD = pipeFD[0];
210 void sendLogMessage(
LogConfig::ELogLevel logLevel,
int debugLevel,
const std::string& name,
const std::string& indent,
216 boost::algorithm::trim_right(message);
218 while (!message.empty()) {
219 std::string new_message = boost::algorithm::trim_left_copy_if(message, boost::algorithm::is_any_of(
" \t\r"));
220 if (new_message.empty()) {
221 message = new_message;
222 }
else if (new_message[0] ==
'\n') {
223 message = new_message.substr(1, std::string::npos);
229 if (message.empty())
return;
231 boost::algorithm::replace_all(message,
"\n",
"\n" + indent);
233 B2LOG(logLevel, debugLevel,
"Output from " << name <<
":\n" << indent << message);
int m_savedFD
Saved file descriptor: a duplicate of the file descriptor of m_fileObject.
bool start()
start intercepting the stream.
~StreamInterceptor()
close file descriptors
DiscardStream(std::ostream &stream, FILE *fileObject)
Create StreamInterceptor which will redirect to /dev/null.
~CaptureStream()
Close file descriptors.
int m_stdoutDebugLevel
debug level for the log message to be emitted for output on stdout if m_stdoutLevel is c_Debug
void removeObject(CaptureStream *obj)
Remove a CaptureStream object to no longer guard against SIGABRT.
FILE * m_fileObject
File object of the file we want to replace, needed to obtain file descriptor and to flush.
int m_stderrDebugLevel
debug level for the log message to be emitted for output on stderr if m_stderrLevel is c_Debug
void setReplacementFD(int fd)
set the replacement file descriptor, should be called in the constructor of derived classes
CaptureStreamAbortHandler()
Register handler.
LogConfig::ELogLevel m_stdoutLevel
severity of the log message to be emitted for output on stdout
bool finish()
Restore the stream and get the output from the pipe.
bool finish()
Finish the capture and emit the message if output has appeard on stdout or stderr.
std::string m_outputStr
string with the output, only filled after finish()
std::string m_indent
Identation to add to the beginning of each line of output.
ELogLevel
Definition of the supported log levels.
CaptureStream(std::ostream &stream, FILE *fileObject)
Create a StreamInterceptor which writes into a pipe.
std::set< CaptureStream * > m_objects
list of all active stream redirections
bool finish()
Finish intercepting the output.
int m_replacementFD
Replacement file descriptor to be used while capturing.
const std::string & getStdOut() const
Return the captured stdout output if any.
Class to capture anything written to stream into a string.
bool finish()
stop intercepting the stream.
LogConfig::ELogLevel m_stderrLevel
severity of the log message to be emitted for output on stderr
const std::string & getStdErr() const
Return the captured stderr output if any.
Encapsulate all classes needed to intercept stdout and stderr.
Base class with all necessary features to intercept output to a file descriptor.
const std::string m_name
Name of the output producing tool/library.
static LogSystem & Instance()
Static method to get a reference to the LogSystem instance.
int m_pipeReadFD
file descriptor of the read end of the pipe
std::ostream & m_stream
C++ stream object, only needed to flush before replacement.
static void handle(int signal)
signal handler: print all pending redirection buffers and exit
static CaptureStreamAbortHandler & getInstance()
Return the singleton instance.
bool start()
Start intercepting the output.
void addObject(CaptureStream *obj)
Add a CaptureStream object to guard against SIGABRT.
CaptureStreamAbortHandler & operator=(const CaptureStreamAbortHandler &)=delete
Singleton, no assignment.
bool replaceFD(int fileDescriptor)
Replace the file descriptor of m_fileObject with the one passed.
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.
StreamInterceptor(std::ostream &stream, FILE *fileObject)
Construct keeping a reference to the std::ostream and the file descriptor which are associated with t...