diff options
-rw-r--r-- | nxcomp/src/Log.cpp | 53 | ||||
-rw-r--r-- | nxcomp/src/Log.h | 59 |
2 files changed, 89 insertions, 23 deletions
diff --git a/nxcomp/src/Log.cpp b/nxcomp/src/Log.cpp index 24f660507..a3a7222ef 100644 --- a/nxcomp/src/Log.cpp +++ b/nxcomp/src/Log.cpp @@ -106,16 +106,53 @@ std::string NXLog::stamp_to_string(const NXLogStamp& stamp) const NXLog& operator<< (NXLog& out, const NXLogStamp& value) { - out.current_level( value.level() ); - out.current_file( value.file() ); + /* + * If appending, the file and function names must be empty and + * the line set to zero. + */ + const bool looks_like_append = ((value.file().empty()) || (value.function().empty()) || (0 == value.line())); + const bool append = ((looks_like_append) && ((value.file().empty()) && (value.function().empty()) && (0 == value.line()))); + + if ((looks_like_append) && (!append)) + { + std::cerr << "WARNING: At least one element in logstamp invalid, but this is not supposed to be an append operation. " + << "Internal state error!\n" << "Log line will be discarded!" << std::endl; + } + else if (append) + { + /* Appending means that the log object's internal level and the message level must match. */ + if (out.current_level() == value.level()) + { + /* And the buffer must of course be non-empty. */ + if (out.has_buffer()) + { + out << " (cont.) "; + } + else + { + std::cerr << "WARNING: Append operation requested, but no queued data available. " + << "Internal state error!\n" << "Log line will be discarded!" << std::endl; + } + } + else + { + std::cerr << "WARNING: Append operation requested, but internal log level not matching line level. " + << "Internal state error!\n" << "Log line will be discarded!" << std::endl; + } + } + else + { + out.current_level( value.level() ); + out.current_file( value.file() ); - // Writing an NXLogStamp to the stream indicates the start of a new entry. - // If there's any content in the buffer and we actually intend to keep that line, - // create a new entry in the output queue. - if ( out.synchronized() && out.will_log() ) - out.new_stack_entry(); + // Writing an NXLogStamp to the stream indicates the start of a new entry. + // If there's any content in the buffer and we actually intend to keep that line, + // create a new entry in the output queue. + if ( out.synchronized() && out.will_log() ) + out.new_stack_entry(); - out << out.stamp_to_string(value); + out << out.stamp_to_string(value); + } return out; } diff --git a/nxcomp/src/Log.h b/nxcomp/src/Log.h index 68680697f..9781ec8b2 100644 --- a/nxcomp/src/Log.h +++ b/nxcomp/src/Log.h @@ -105,7 +105,7 @@ class NXLogStamp } - NXLogStamp(const char *file, const char *function, size_t line, NXLogLevel level) : file_(file), function_(function), line_(line), level_(level) + NXLogStamp(NXLogLevel level, const char *file = "", const char *function = "", size_t line = 0) : file_(file), function_(function), line_(line), level_(level) { gettimeofday(×tamp_, NULL); } @@ -432,6 +432,11 @@ class NXLog */ bool will_log() const; + bool has_buffer() const + { + return (!(get_data()->buffer.empty ())); + } + /** * This catches std::flush @@ -442,10 +447,19 @@ class NXLog { if ( synchronized() ) { - per_thread_data *pdt = get_data(); - assert (!pdt->buffer.empty ()); - (*pdt->buffer.top()) << F; - flush(); + /* Verbosely discard data if we don't have a buffer. */ + if (!(has_buffer())) + { + std::cerr << "WARNING: no buffer available! " + << "Internal state error!\n" << "Log hunk will be discarded!" << std::endl; + } + else + { + per_thread_data *pdt = get_data(); + assert (!pdt->buffer.empty ()); + (*pdt->buffer.top()) << F; + flush(); + } } else { @@ -466,7 +480,8 @@ class NXLog extern NXLog nx_log; -#define nxstamp(l) NXLogStamp(__FILE__, __func__, __LINE__, l) +#define nxstamp(l) NXLogStamp(l, __FILE__, __func__, __LINE__) +#define nxstamp_append(l) NXLogStamp(l) #define nxdbg nx_log << nxstamp(NXDEBUG) @@ -475,6 +490,12 @@ extern NXLog nx_log; #define nxerr nx_log << nxstamp(NXERROR) #define nxfatal nx_log << nxstamp(NXFATAL) +/* Append data to already existing (i.e., same-level) line. */ +#define nxdbg_append nx_log << nxstamp_append(NXDEBUG) +#define nxinfo_append nx_log << nxstamp_append(NXINFO) +#define nxwarn_append nx_log << nxstamp_append(NXWARNING) +#define nxerr_append nx_log << nxstamp_append(NXERROR) +#define nxfatal_append nx_log << nxstamp_append(NXFATAL) NXLog& operator<< (NXLog& out, const NXLogStamp& value); @@ -520,16 +541,24 @@ NXLog& operator<<(NXLog& out, const T& value) { if ( out.synchronized() ) { - // In synchronized mode, we buffer data until a newline, std::flush, or the buffer - // gets full. Then we dump the whole thing at once to the output stream, synchronizing - // with a mutex. - NXLog::per_thread_data *pdt = out.get_data(); - assert (!pdt->buffer.empty ()); - (*pdt->buffer.top()) << value; - - if ( ss_length(pdt->buffer.top()) >= out.thread_buffer_size_ || has_newline(value) ) - out.flush(); + /* Verbosely discard data if we don't have a buffer. */ + if (!(out.has_buffer())) + { + std::cerr << "WARNING: no buffer available! " + << "Internal state error!\n" << "Log hunk will be discarded!" << std::endl; + } + else + { + // In synchronized mode, we buffer data until a newline, std::flush, or the buffer + // gets full. Then we dump the whole thing at once to the output stream, synchronizing + // with a mutex. + NXLog::per_thread_data *pdt = out.get_data(); + assert (!pdt->buffer.empty ()); + (*pdt->buffer.top()) << value; + if ( ss_length(pdt->buffer.top()) >= out.thread_buffer_size_ || has_newline(value) ) + out.flush(); + } } else { |