aboutsummaryrefslogtreecommitdiff
path: root/nxcomp/src
diff options
context:
space:
mode:
authorMihai Moldovan <ionic@ionic.de>2017-12-24 22:16:38 +0100
committerMihai Moldovan <ionic@ionic.de>2017-12-25 04:00:36 +0100
commitdccf5901ec1bbdcd5523169ca20751d9b7569e7d (patch)
tree9c53c3016a1fedc36c83bb2386ba6a30c9eb0ecc /nxcomp/src
parentb30cfaa24d28dfcf5ee67d33cb614c9800bbddd2 (diff)
downloadnx-libs-dccf5901ec1bbdcd5523169ca20751d9b7569e7d.tar.gz
nx-libs-dccf5901ec1bbdcd5523169ca20751d9b7569e7d.tar.bz2
nx-libs-dccf5901ec1bbdcd5523169ca20751d9b7569e7d.zip
nxcomp/src/Log.{cpp,h}: provide infrastructure for appending to already existing log lines.
Also handle errors due to missing buffers gracefully. This error is surprisingly easy to trigger, so we should make sure that the program does not crash.
Diffstat (limited to 'nxcomp/src')
-rw-r--r--nxcomp/src/Log.cpp53
-rw-r--r--nxcomp/src/Log.h59
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(&timestamp_, 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
{