From: <sv...@ww...> - 2005-12-23 05:49:18
|
Author: mkrose Date: 2005-12-22 21:49:10 -0800 (Thu, 22 Dec 2005) New Revision: 1798 Modified: trunk/CSP/csp/csplib/util/Log.h trunk/CSP/csp/csplib/util/LogStream.cpp trunk/CSP/csp/csplib/util/LogStream.h Log: A somewhat more robust solution to ensure that logs are properly flushed on exit. Browse at: https://www.zerobar.net/viewcvs/viewcvs.cgi?view=rev&rev=1798 Modified: trunk/CSP/csp/csplib/util/Log.h =================================================================== --- trunk/CSP/csp/csplib/util/Log.h 2005-12-23 04:34:08 UTC (rev 1797) +++ trunk/CSP/csp/csplib/util/Log.h 2005-12-23 05:49:10 UTC (rev 1798) @@ -49,6 +49,7 @@ // it is safe to log messages from static destructors. log_stream = LogStream::getOrCreateNamedLog("CSP"); log_stream->initFromEnvironment("CSPLOG_FILE", "CSPLOG_PRIORITY", "CSPLOG_FLAGS"); + log_stream->setNeverDeleted(); } return *log_stream; } Modified: trunk/CSP/csp/csplib/util/LogStream.cpp =================================================================== --- trunk/CSP/csp/csplib/util/LogStream.cpp 2005-12-23 04:34:08 UTC (rev 1797) +++ trunk/CSP/csp/csplib/util/LogStream.cpp 2005-12-23 05:49:10 UTC (rev 1798) @@ -89,9 +89,55 @@ *buffer = 0; } +/** A private singleton used as a hook at static destruction to force + * logstreams that will never be deleted to enter autoflush mode. + * This ensures that the log will not be truncated when the program + * terminates. LogStreams that are allocated on the heap and never + * deleted should be registered with this helper by calling + * setNeverDeleted(). + */ +class AutoFlushAtExitHelper { + // lazy construction to ensure proper initialization during static + // construction. + static std::vector<LogStream*> *m_streams; + static Mutex *m_mutex; +public: + // warning: this is not thread-safe! + static void registerStream(LogStream* stream) { + if (!m_mutex) m_mutex = new Mutex; + if (!m_streams) m_streams = new std::vector<LogStream*>; + m_mutex->lock(); + m_streams->push_back(stream); + m_mutex->unlock(); + } + AutoFlushAtExitHelper() { + // force initialization in case no streams are registered during + // static construction. + if (!m_mutex) m_mutex = new Mutex; + if (!m_streams) m_streams = new std::vector<LogStream*>; + } + ~AutoFlushAtExitHelper() { + for (std::vector<LogStream*>::iterator iter = m_streams->begin(); iter != m_streams->end(); ++iter) { + (*iter)->setAlwaysFlush(true); + (*iter)->flush(); + } + delete m_streams; + delete m_mutex; + } +} AutoFlushAtExit; // static instance + +std::vector<LogStream*> *AutoFlushAtExitHelper::m_streams; +Mutex *AutoFlushAtExitHelper::m_mutex; + +} // namespace + +void LogStream::setNeverDeleted() { + if (!m_never_deleted) { + AutoFlushAtExitHelper::registerStream(this); + m_never_deleted = true; + } } - void LogStream::initFromEnvironment(const char *log_file, const char *log_priority, const char *log_flags) { if (log_file) { char *env_logfile = getenv(log_file); @@ -187,7 +233,9 @@ m_stream(&std::cerr), m_fstream(0), m_mutex(0), - m_throw_on_fatal(false) { + m_throw_on_fatal(false), + m_autoflush(false), + m_never_deleted(false) { init(); } @@ -197,13 +245,16 @@ m_categories(~0), m_stream(&stream), m_fstream(0), - m_mutex(0) { + m_mutex(0), + m_autoflush(false), + m_never_deleted(false) { init(); } LogStream::~LogStream() { close(); delete m_mutex; + assert(!m_never_deleted); } void LogStream::setStream(std::ostream &stream) { Modified: trunk/CSP/csp/csplib/util/LogStream.h =================================================================== --- trunk/CSP/csp/csplib/util/LogStream.h 2005-12-23 04:34:08 UTC (rev 1797) +++ trunk/CSP/csp/csplib/util/LogStream.h 2005-12-23 05:49:10 UTC (rev 1798) @@ -115,7 +115,6 @@ */ void setThrowOnFatal(bool throw_on_fatal=true) { m_throw_on_fatal = throw_on_fatal; } - /** Test if a given priority and category should be logged. */ inline bool isNoteworthy(int priority, int category=~0) { @@ -133,13 +132,25 @@ */ static LogStream *getOrCreateNamedLog(const std::string &name); - /** Helper class used to write a single entry to the log stream. The * class constructs the log entry as a string internally, then writes * it to the LogStream when it goes out of scope. */ class LogEntry; + /** Call for logstreams that are allocated on the heap and never deleted + * to ensure that log messages will be properly flushed during static + * destruction at program exit. + */ + void setNeverDeleted(); + + /** Call to force the log to be flushed after each entry. Note that + * constant flushing is very inefficient. This method is primarily + * used internally in conjunction with setNeverDeleted. + */ + void setAlwaysFlush(bool flush) { m_autoflush = flush; } + inline bool autoflush() const { return m_autoflush; } + private: void init(); void close(); @@ -154,6 +165,9 @@ bool m_threadsafe; uint64 m_initial_thread; bool m_throw_on_fatal; + + bool m_autoflush; + bool m_never_deleted; }; @@ -221,7 +235,7 @@ ~LogEntry() { m_stream.lock(); m_stream.getStream() << m_buffer.get() << "\n"; - if (m_priority >= LogStream::cWarning) m_stream.flush(); + if (m_priority >= LogStream::cWarning || m_stream.autoflush()) m_stream.flush(); m_stream.unlock(); if (m_priority == LogStream::cFatal) die(); } |