]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Added Raw, an std::ostream manipulator to print possibly non-terminated buffers
authorAlex Rousskov <rousskov@measurement-factory.com>
Fri, 14 Dec 2012 16:07:18 +0000 (09:07 -0700)
committerAlex Rousskov <rousskov@measurement-factory.com>
Fri, 14 Dec 2012 16:07:18 +0000 (09:07 -0700)
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.

src/Debug.h
src/debug.cc
src/tests/stub_debug.cc

index 3df1cfc0defe0f666fa7ffb16b99bca8a86a097f..e772b467f79400079bfab2793cafebb29926743b 100644 (file)
@@ -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 */
index 7a639ef567b69d54fffa2c17c05960a7afe68178..83ab4ecd4525155ef6e84694b8676a248ce491e7 100644 (file)
@@ -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;
+}
index 50e73fe225cb258d0375b276c79c35b404adb3a2..c7f6133ca0e2c491b383c09e407bb769f79a685b 100644 (file)
@@ -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;
+}