[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