[asterisk-scf-commits] asterisk-scf/integration/log4scf.git branch "master" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Wed Sep 22 17:01:19 CDT 2010


branch "master" has been updated
       via  edf236ccc7ed61007089f6c72711972d333357e1 (commit)
       via  c5f96ec0447f23b6aaca938d28efc91c7171f957 (commit)
       via  f3db9df597ca5af93fe984189ba0330945cd4639 (commit)
       via  034f0e6656c09939da144efbb76a57408f522fc5 (commit)
      from  68bc29e4bb2cf9f390df51d1f7f3ed1d7ee3fd6f (commit)

Summary of changes:
 client/src/Logger.cpp        |   52 +++++++++++++++++++++--
 client/src/LoggerFactory.cpp |    2 +
 client/src/logger.h          |   97 ++++++++++++++++++++++++++++++++++++++++++
 client/test/CMakeLists.txt   |    1 +
 client/test/ExpectedLogOut.h |   50 +++++++++++++++++++++
 client/test/LogBuf-test.cpp  |   39 +++++++++++++++++
 client/test/Logger-test.cpp  |   76 ++++++++++++++++++++------------
 ice/log4scf.ice              |    9 ++++
 server/src/LoggingServer.cpp |   80 ++++++++++++++++++++---------------
 server/src/LoggingServer.h   |   14 ++++++
 10 files changed, 353 insertions(+), 67 deletions(-)
 create mode 100644 client/test/ExpectedLogOut.h
 create mode 100644 client/test/LogBuf-test.cpp


- Log -----------------------------------------------------------------
commit edf236ccc7ed61007089f6c72711972d333357e1
Author: David M. Lee <dlee at digium.com>
Date:   Wed Sep 22 16:27:30 2010 -0500

    Streaming output is working.  logger(Info) << "Working!";

diff --git a/client/src/Logger.cpp b/client/src/Logger.cpp
index aec08ad..7a6a27d 100644
--- a/client/src/Logger.cpp
+++ b/client/src/Logger.cpp
@@ -18,9 +18,48 @@ LogOut::~LogOut()
    // no-op
 }
 
+LogBuf::LogBuf(LogOut &out, std::string const &source, Level logLevel) :
+   out(out), source(source), logLevel(logLevel)
+{
+}
+
+LogBuf::LogBuf(LogBuf const &orig) :
+   out(orig.out), source(orig.source), logLevel(orig.logLevel)
+{
+   buffer.str(orig.buffer.str());
+}
+
+LogBuf::~LogBuf()
+{
+   if (!buffer.str().empty())
+   {
+      sendBuffer();
+   }
+}
+
+int LogBuf::overflow(int c)
+{
+   if (c == '\n' || c == traits_type::eof())
+   {
+      sendBuffer();
+      return c;
+   }
+   return buffer.sputc(c);
+}
+
+void LogBuf::sendBuffer()
+{
+   // logic looks a bit backwards, but that's in case out.logs()
+   // throws an exception, we still want to clear the buffer.
+   std::string const &message = buffer.str();
+   buffer.str("");
+   // send
+   out.logs(source, logLevel, message);
+}
+
+
 Logger::Logger(std::string const &name, LogOut &out, Level logLevel) :
-   parent(0), name(name), out(out), logLevel(logLevel),
-         inheritedLevel(false)
+   parent(0), name(name), out(out), logLevel(logLevel), inheritedLevel(false)
 {
 }
 
@@ -32,6 +71,11 @@ Logger::Logger(Logger const &parent, std::string const &name) :
    assert(name.find(parent.name) == 0);
 }
 
+CondStream Logger::operator()(Level level) const
+{
+   return CondStream(out, name, level, isEnabledFor(level));
+}
+
 void Logger::logs(Level level, std::string const &message) const
 {
    if (isEnabledFor(level))
@@ -99,8 +143,8 @@ Logger &Logger::getChild(std::string const &childName)
    Logger *&child = children[childName];
    if (child == 0)
    {
-      std::string fullName = getName().empty() ? childName
-         : getName() + "." + childName;
+      std::string fullName = getName().empty() ? childName : getName() + "."
+            + childName;
       child = new Logger(*this, fullName);
    }
    return *child;
diff --git a/client/src/logger.h b/client/src/logger.h
index ca5a867..01bfbb4 100644
--- a/client/src/logger.h
+++ b/client/src/logger.h
@@ -33,6 +33,95 @@ public:
 };
 
 /**
+ * A streambuf for writing to a LogOut.  Messages are written at newlines (\n)
+ * or when destroyed.  The way temporary object lifecycles work in C++, this is
+ * very convenient.
+ */
+class LogBuf : public std::streambuf
+{
+public:
+   LogBuf(LogOut &out, std::string const &source, Level logLevel);
+
+   /**
+    * Copy ctor.
+    * @param orig Original.
+    */
+   LogBuf(LogBuf const &orig);
+
+   ~LogBuf();
+
+protected:
+   int overflow(int c);
+
+private:
+   std::stringbuf buffer;
+   LogOut &out;
+   const std::string source;
+   const Level logLevel;
+
+   /**
+    * Sends the current buffer to out and clears it.
+    */
+   void sendBuffer();
+};
+
+/**
+ * A ostream-like thing which will only process output if enabled.  When
+ * disabled, it very efficiently ignores operator<<() calls.
+ */
+class CondStream
+{
+public:
+   CondStream(LogOut &out, std::string const &source, Level logLevel,
+              bool enabled) :
+      buf(out, source, logLevel), stream(&buf), enabled(enabled)
+   {
+   }
+
+   /**
+    * Copy ctor.
+    * @param orig Original.
+    */
+   CondStream(CondStream const &orig) :
+      buf(orig.buf), stream(&buf), enabled(orig.enabled)
+   {
+
+   }
+
+   /**
+    * Output operator.  Only does something when enabled == true.
+    * @param val Value to output.
+    * @return this.
+    */
+   template<typename T>
+   CondStream &operator<<(T const &val);
+
+private:
+   /**
+    * streambuffer for writing characters.
+    */
+   LogBuf buf;
+   /**
+    * Ostream for processing output.
+    */
+   std::ostream stream;
+   /**
+    * If false, operator<<() does nothing.
+    */
+   bool enabled;
+};
+
+template<typename T>
+inline CondStream &CondStream::operator<<(T const &val)
+{
+   if (enabled)
+   {
+      stream << val;
+   }
+   return *this;
+}
+
+/**
  * The Logger for a particular Source.
  */
 class Logger
@@ -60,6 +149,14 @@ public:
    }
 
    /**
+    * Ostream style logging.
+    *
+    * @param level Level for messages sent to this stream.
+    * @return LogStream that logs at the given level.
+    */
+   CondStream operator()(Level level) const;
+
+   /**
     * Log a single message.
     */
    void logs(Level level, std::string const &message) const;
diff --git a/client/test/CMakeLists.txt b/client/test/CMakeLists.txt
index b7d8bbf..099d451 100644
--- a/client/test/CMakeLists.txt
+++ b/client/test/CMakeLists.txt
@@ -13,6 +13,7 @@ include_directories(../../common)
 
 hydra_component_add_file(logging-client-test Logger-test.cpp)
 hydra_component_add_file(logging-client-test LoggerFactory-test.cpp)
+hydra_component_add_file(logging-client-test LogBuf-test.cpp)
 hydra_component_add_file(logging-client-test client-test.cpp)
 
 hydra_component_add_boost_libraries(logging-client-test unit_test_framework)
diff --git a/client/test/ExpectedLogOut.h b/client/test/ExpectedLogOut.h
new file mode 100644
index 0000000..a7a051e
--- /dev/null
+++ b/client/test/ExpectedLogOut.h
@@ -0,0 +1,50 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+
+#pragma once
+
+#include "logger.h"
+
+namespace AsteriskSCF
+{
+namespace System
+{
+namespace Logging
+{
+
+/**
+ * Mock class to check the output that makes it to a LogOut interface.
+ */
+class ExpectedLogOut : public LogOut
+{
+public:
+   ExpectedLogOut(std::string const &expected) :
+      expected(expected)
+   {
+   }
+
+   void logs(std::string const &source, Level logLevel,
+             std::string const &message)
+   {
+      actual << source << ":" << logLevel << ":" << message << '\n';
+   }
+
+   void check()
+   {
+      BOOST_CHECK_EQUAL(expected, actual.str());
+   }
+
+private:
+   std::string expected;
+   std::stringstream actual;
+};
+
+
+} // Logging
+} // System
+} // AsteriskSCF
diff --git a/client/test/LogBuf-test.cpp b/client/test/LogBuf-test.cpp
new file mode 100644
index 0000000..8979aef
--- /dev/null
+++ b/client/test/LogBuf-test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+
+
+#include <boost/test/unit_test.hpp>
+
+#include "logger.h"
+#include "ExpectedLogOut.h"
+
+using namespace AsteriskSCF::System::Logging;
+
+BOOST_AUTO_TEST_SUITE(LogStreamTest)
+
+BOOST_AUTO_TEST_CASE(test_stream)
+{
+   ExpectedLogOut out("src:Info:testing\n");
+   LogBuf uut(out, "src", Info);
+   std::ostream stream(&uut);
+
+   stream << "testing" << '\n';
+   out.check();
+}
+
+BOOST_AUTO_TEST_CASE(test_stream_format)
+{
+   ExpectedLogOut out("src:Debug:debug f00d\n");
+   LogBuf buf(out, "src", Debug);
+   std::ostream uut(&buf);
+
+   uut << "debug " << std::hex << 61453 << '\n';
+   out.check();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/client/test/Logger-test.cpp b/client/test/Logger-test.cpp
index 2984862..0216dcd 100644
--- a/client/test/Logger-test.cpp
+++ b/client/test/Logger-test.cpp
@@ -6,41 +6,13 @@
  * All rights reserved.
  */
 
-#include <sstream>
-
 #include <boost/test/unit_test.hpp>
 
 #include "logger.h"
+#include "ExpectedLogOut.h"
 
 using namespace AsteriskSCF::System::Logging;
 
-namespace
-{
-class ExpectedLogOut : public LogOut
-{
-public:
-   ExpectedLogOut(std::string const &expected) :
-      expected(expected)
-   {
-   }
-
-   void logs(std::string const &source, Level logLevel,
-             std::string const &message)
-   {
-      actual << source << ":" << logLevel << ":" << message << '\n';
-   }
-
-   void check()
-   {
-      BOOST_CHECK_EQUAL(expected, actual.str());
-   }
-
-private:
-   std::string expected;
-   std::stringstream actual;
-};
-}
-
 BOOST_AUTO_TEST_SUITE( LoggerTest )
 
 BOOST_AUTO_TEST_CASE( test_log )
@@ -79,4 +51,50 @@ BOOST_AUTO_TEST_CASE( test_log_squelched )
    out.check();
 }
 
+BOOST_AUTO_TEST_CASE(test_stream_on)
+{
+   ExpectedLogOut out("src:Debug:debug\n");
+   Logger uut("src", out, Debug);
+
+   uut(Debug) << "debug\n";
+   out.check();
+}
+
+BOOST_AUTO_TEST_CASE(test_stream_off)
+{
+   ExpectedLogOut out("");
+   Logger uut("src", out, Info);
+
+   uut(Debug) << "debug\n";
+   out.check();
+}
+
+BOOST_AUTO_TEST_CASE(test_stream)
+{
+   ExpectedLogOut out("src:Info:testing\n");
+   Logger uut("src", out, Info);
+
+   uut(Info) << "testing" << '\n';
+   out.check();
+}
+
+BOOST_AUTO_TEST_CASE(test_stream_format)
+{
+   ExpectedLogOut out("src:Debug:debug f00d\n");
+   Logger uut("src", out, Debug);
+
+   uut(Debug) << "debug " << std::hex << 61453 << '\n';
+   out.check();
+}
+
+BOOST_AUTO_TEST_CASE(test_stream_lots)
+{
+   ExpectedLogOut out("src:Debug:debug\nsrc:Info:info\n");
+   Logger uut("src", out, Debug);
+
+   uut(Debug) << "debug";
+   uut(Info) << "info";
+   out.check();
+}
+
 BOOST_AUTO_TEST_SUITE_END()

commit c5f96ec0447f23b6aaca938d28efc91c7171f957
Author: David M. Lee <dlee at digium.com>
Date:   Wed Sep 22 16:26:53 2010 -0500

    Server-side clean ups.

diff --git a/server/src/LoggingServer.cpp b/server/src/LoggingServer.cpp
index 5fc8a37..0045fb6 100644
--- a/server/src/LoggingServer.cpp
+++ b/server/src/LoggingServer.cpp
@@ -44,32 +44,13 @@ Level LoggingServerI::getEffectiveLevel(std::string const &source) const
    // this is they the map is reverse sorted.  find the first entry where
    // the source key is a substring of the source we're looking for, where
    // the substring
-   Sources::const_iterator i = sources.lower_bound(source);
-
-   while (i != sources.end())
+   for (Sources::const_iterator i = sources.lower_bound(source);
+         i != sources.end(); ++i)
    {
-      std::string const &key = i->first;
-      // if key is subkey of source
-      // avoid coincidental matches (i.e. "A" is not a subkey of "AA")
-      if (source.compare(0, key.size(), key) == 0)
+      if (isSubpathOf(source, i->first))
       {
-         if (source.size() == key.size())
-         {
-            // exact match
-            return i->second.getLevel();
-         }
-         if (key.empty())
-         {
-            // matches default setting
-            return i->second.getLevel();
-         }
-         if (source[key.length()] == '.')
-         {
-            // matches subkey
-            return i->second.getLevel();
-         }
+         return i->second.getLevel();
       }
-      ++i;
    }
 
    // Since "" is in the map, this should never run.
@@ -88,22 +69,53 @@ void LoggingServerI::logs(std::string const &source, Level level,
 {
    if (isEnabledFor(source, level))
    {
-      // date level source(1) message
-      std::string::size_type lastDot = source.rfind('.');
-      if (lastDot == std::string::npos)
+      reallyLog(source, level, message);
+   }
+}
+
+void LoggingServerI::reallyLog(std::string const &source, Level level,
+                               const std::string &message) const
+{
+   // date level source(1) message
+   std::string::size_type lastDot = source.rfind('.');
+   if (lastDot == std::string::npos)
+   {
+      lastDot = -1;
+   }
+   std::string lastSource = source.substr(lastDot + 1);
+   {
+      IceUtil::Mutex::Lock sourcesLock(outputMutex);
+      std::ostream::fmtflags flags = std::cout.flags();
+      std::cout << getCurrentTime() << ' ' << std::setw(9) << level << ' '
+            << std::setw(9) << std::left << lastSource << ' ' << message
+            << '\n';
+      std::cout.flags(flags);
+   }
+}
+
+bool LoggingServerI::isSubpathOf(std::string const &path,
+                                 std::string const &subpath)
+{
+   // if path begins with subpath
+   if (path.compare(0, subpath.size(), subpath) == 0)
+   {
+      // if matched default setting
+      if (subpath.empty())
+      {
+         return true;
+      }
+      // if exact match
+      if (path.size() == subpath.size())
       {
-         lastDot = -1;
+         return true;
       }
-      std::string lastSource = source.substr(lastDot + 1);
+      // if subpath
+      if (path[subpath.length()] == '.')
       {
-         IceUtil::Mutex::Lock sourcesLock(outputMutex);
-         std::ostream::fmtflags flags = std::cout.flags();
-         std::cout << getCurrentTime() << ' ' << std::setw(9) << level << ' '
-               << std::setw(9) << std::left << lastSource << ' ' << message
-               << '\n';
-         std::cout.flags(flags);
+         return true;
       }
    }
+   return false;
 }
 
 // <prefix>.logger=level
diff --git a/server/src/LoggingServer.h b/server/src/LoggingServer.h
index 12ebd89..6d9eeb9 100644
--- a/server/src/LoggingServer.h
+++ b/server/src/LoggingServer.h
@@ -75,6 +75,20 @@ private:
    typedef std::map<std::string, SourceNode, std::greater<std::string> >
          Sources;
 
+   /**
+    * Unconditionally logs the given message.
+    */
+   void reallyLog(std::string const &, Level, const std::string&) const;
+
+   /**
+    * Returns true is subpath is a subpath of path.
+    *
+    * @param path Full path to search.
+    * @param subpath Subpath to look for.
+    * @return true if subpath is a subpath of path.
+    */
+   static bool isSubpathOf(std::string const &path, std::string const &subpath);
+
    IceUtil::Mutex sourcesMutex;
    IceUtil::Mutex outputMutex;
    Sources sources;

commit f3db9df597ca5af93fe984189ba0330945cd4639
Author: David M. Lee <dlee at digium.com>
Date:   Wed Sep 22 10:59:11 2010 -0500

    Commented Level's

diff --git a/ice/log4scf.ice b/ice/log4scf.ice
index 6a2ffc5..c70909f 100644
--- a/ice/log4scf.ice
+++ b/ice/log4scf.ice
@@ -19,14 +19,23 @@ module Logging
     */
    enum Level
    {
+      /** debug-level messages */
       Debug,
+      /** informational messages */
       Info,
+      /** normal but significant condition */
       Notice,
+      /** warning conditions */
       Warning,
+      /** error conditions */
       Error,
+      /** critical conditions */
       Critical,
+      /** action must be taken immediately */
       Alert,
+      /** system is unusable */
       Emergency,
+      /** phony level; only to be used in setting log levels */
       Off
    };
 

commit 034f0e6656c09939da144efbb76a57408f522fc5
Author: David M. Lee <dlee at digium.com>
Date:   Wed Sep 22 09:28:09 2010 -0500

    Commented most recent change, to avoid overzealous optimization in the future.

diff --git a/client/src/LoggerFactory.cpp b/client/src/LoggerFactory.cpp
index 7e52698..4bf03cb 100644
--- a/client/src/LoggerFactory.cpp
+++ b/client/src/LoggerFactory.cpp
@@ -29,6 +29,8 @@ LoggerFactory::LoggerFactory(LogOut &out) :
 Logger &LoggerFactory::getLogger(std::string const &source)
 {
    std::vector<std::string> path;
+   // older versions of boost output a single entry when splitting an empty
+   // string
    if (!source.empty())
    {
       split(path, source, std::bind1st(std::equal_to<char>(), '.'));

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/log4scf.git



More information about the asterisk-scf-commits mailing list