From: Alex Rousskov Date: Fri, 14 Dec 2012 16:07:18 +0000 (-0700) Subject: Added Raw, an std::ostream manipulator to print possibly non-terminated buffers X-Git-Tag: SQUID_3_4_0_1~439 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=be039a686bacba55fa755ace9e9f51116ef4d30d;p=thirdparty%2Fsquid.git Added Raw, an std::ostream manipulator to print possibly non-terminated buffers and their labels/sizes. The Raw manipulator tries to be smart about printing buffers at various debugging levels: Large buffers are only printed at DBG_DATA by default. This allows the caller to mix higher-level debug messages with dumping of potentially large volumes of data. This smartness can be overruled using an explicit minLevel() method call. --- diff --git a/src/Debug.h b/src/Debug.h index 3df1cfc0de..e772b467f7 100644 --- a/src/Debug.h +++ b/src/Debug.h @@ -81,7 +81,8 @@ public: static char *cache_log; static int rotateNumber; static int Levels[MAX_DEBUG_SECTIONS]; - static int level; + static int level; ///< minimum debugging level required by debugs() call + static int sectionLevel; ///< maximum debugging level allowed now static int override_X; static int log_stderr; static bool log_syslog; @@ -107,6 +108,7 @@ const char * SkipBuildPrefix(const char* path); #define debugs(SECTION, LEVEL, CONTENT) \ do { \ if ((Debug::level = (LEVEL)) <= Debug::Levels[SECTION]) { \ + Debug::sectionLevel = Debug::Levels[SECTION]; \ std::ostream &_dbo=Debug::getDebugOut(); \ if (Debug::level > DBG_IMPORTANT) \ _dbo << SkipBuildPrefix(__FILE__)<<"("<<__LINE__<<") "<<__FUNCTION__<<": "; \ @@ -157,4 +159,42 @@ void _db_print(const char *,...) PRINTF_FORMAT_ARG1; void _db_set_syslog(const char *facility); void _db_rotate_log(void); + +/// Prints raw and/or non-terminated data safely, efficiently, and beautifully. +/// Allows raw data debugging in debugs() statements with low debugging levels +/// by printing only if higher section debugging levels are configured: +/// debugs(11, DBG_IMPORTANT, "always printed" << Raw(may be printed...)); +class Raw { +public: + Raw(const char *label, const char *data, const size_t size): + level(-1), label_(label), data_(data), size_(size) {} + + /// limit data printing to at least the given debugging level + Raw &minLevel(const int aLevel) { level = aLevel; return *this; } + + /// If debugging is prohibited by the current debugs() or section level, + /// prints nothing. Otherwise, dumps data using one of these formats: + /// " label[size]=data" if label was set and data size is positive + /// " label[0]" if label was set and data size is zero + /// " data" if label was not set and data size is positive + /// "" (i.e., prints nothing) if label was not set and data size is zero + std::ostream &print(std::ostream &os) const; + + /// Minimum section debugging level necessary for printing. By default, + /// small strings are always printed while large strings are only printed + /// if DBG_DATA debugging level is enabled. + int level; + +private: + const char *label_; ///< optional data name or ID; triggers size printing + const char *data_; ///< raw data to be printed + size_t size_; ///< data length +}; + +inline +std::ostream &operator <<(std::ostream &os, const Raw &raw) +{ + return raw.print(os); +} + #endif /* SQUID_DEBUG_H */ diff --git a/src/debug.cc b/src/debug.cc index 7a639ef567..83ab4ecd45 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -45,6 +45,7 @@ int Debug::log_stderr = -1; bool Debug::log_syslog = false; int Debug::Levels[MAX_DEBUG_SECTIONS]; int Debug::level; +int Debug::sectionLevel; char *Debug::cache_log = NULL; int Debug::rotateNumber = -1; FILE *debug_log = NULL; @@ -801,3 +802,26 @@ SkipBuildPrefix(const char* path) return path+BuildPrefixLength; } + +std::ostream & +Raw::print(std::ostream &os) const +{ + if (label_) + os << ' ' << label_ << '[' << size_ << ']'; + + if (!size_) + return os; + + // finalize debugging level if no level was set explicitly via minLevel() + const int finalLevel = (level >= 0) ? level : + (size_ > 40 ? DBG_DATA : Debug::sectionLevel); + if (finalLevel <= Debug::sectionLevel) { + os << (label_ ? '=' : ' '); + if (data_) + os.write(data_, size_); + else + os << "[null]"; + } + + return os; +} diff --git a/src/tests/stub_debug.cc b/src/tests/stub_debug.cc index 50e73fe225..c7f6133ca0 100644 --- a/src/tests/stub_debug.cc +++ b/src/tests/stub_debug.cc @@ -20,6 +20,7 @@ char *Debug::cache_log= NULL; int Debug::rotateNumber = 0; int Debug::Levels[MAX_DEBUG_SECTIONS]; int Debug::level; +int Debug::sectionLevel; int Debug::override_X = 0; int Debug::log_stderr = 1; bool Debug::log_syslog = false; @@ -140,3 +141,23 @@ SkipBuildPrefix(const char* path) { return path; } + +std::ostream & +Raw::print(std::ostream &os) const +{ + if (label_) + os << ' ' << label_ << '[' << size_ << ']'; + + if (!size_) + return os; + + // finalize debugging level if no level was set explicitly via minLevel() + const int finalLevel = (level >= 0) ? level : + (size_ > 40 ? DBG_DATA : Debug::sectionLevel); + if (finalLevel <= Debug::sectionLevel) { + os << (label_ ? '=' : ' '); + os.write(data_, size_); + } + + return os; +}