[asterisk-scf-commits] asterisk-scf/release/logger.git branch "master" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Sep 12 15:33:27 CDT 2011


branch "master" has been updated
       via  43bb75fbdf04568405f509920a69f5799722b5f0 (commit)
      from  a2beb54a44621324d9769a93d190165d4fd3e815 (commit)

Summary of changes:
 client/src/CMakeLists.txt                          |    5 +-
 client/src/IceLogger.cpp                           |   27 +++-
 client/src/LogFormatter.cpp                        |  201 ++++++++++++++++++++
 client/src/Logger.cpp                              |   49 ++++--
 client/src/LoggerFactory.cpp                       |    2 +
 client/src/OstreamLogger.cpp                       |   43 ++++-
 client/test/CMakeLists.txt                         |    1 +
 client/test/ExpectedLogOut.h                       |   29 ++-
 client/test/IceConfigurator-test.cpp               |    4 +-
 client/test/LogBuf-test.cpp                        |    8 +-
 client/test/Logger-test.cpp                        |  105 +++++++++-
 client/test/LoggerFactory-test.cpp                 |    4 +-
 include/AsteriskSCF/Logger/IceLogger.h             |    7 +-
 .../AsteriskSCF/Logger/{LogOut.h => LogConsts.h}   |   20 ++-
 include/AsteriskSCF/Logger/LogFormatter.h          |  104 ++++++++++
 include/AsteriskSCF/Logger/LogOut.h                |    6 +
 include/AsteriskSCF/logger.h                       |   90 +++++----
 server/config/testloggingserver.conf               |   44 ++++-
 server/src/CMakeLists.txt                          |    4 +-
 server/src/ChainedLogOut.cpp                       |   21 +--
 server/src/Configuration.cpp                       |  124 ++++++++++---
 server/src/LoggingServer.cpp                       |   19 ++-
 server/src/LoggingServer.h                         |   16 ++-
 server/test/CMakeLists.txt                         |    4 +-
 server/test/ConfigurationTest.cpp                  |   96 +++++++++-
 server/test/LoggingConfigurationHelper.cpp         |  175 ++++++++++++++----
 server/test/LoggingConfigurationHelper.h           |   11 +-
 .../LoggingService/LoggingConfigurationIf.ice      |   58 ++++++-
 28 files changed, 1082 insertions(+), 195 deletions(-)
 create mode 100644 client/src/LogFormatter.cpp
 copy include/AsteriskSCF/Logger/{LogOut.h => LogConsts.h} (71%)
 create mode 100644 include/AsteriskSCF/Logger/LogFormatter.h


- Log -----------------------------------------------------------------
commit 43bb75fbdf04568405f509920a69f5799722b5f0
Author: Ken Hunt <ken.hunt at digium.com>
Date:   Mon Sep 12 12:02:37 2011 -0500

     Logger formatting support.
      - Integrates the logger formatting support.
     - Updates the formatting to use boost for time and process id handling.
     - Updates the configurator to support setting format.
     - Updates the configurator to support setting the logging level.
     - Updates the tests.

diff --git a/client/src/CMakeLists.txt b/client/src/CMakeLists.txt
index 9cfff78..0b1db78 100644
--- a/client/src/CMakeLists.txt
+++ b/client/src/CMakeLists.txt
@@ -2,15 +2,18 @@ astscf_component_init(logging-client)
 astscf_component_add_files(logging-client Logger.cpp)
 astscf_component_add_files(logging-client LoggerFactory.cpp)
 astscf_component_add_files(logging-client LogOut.cpp)
+astscf_component_add_files(logging-client LogFormatter.cpp)
 astscf_component_add_files(logging-client IceConfigurator.cpp)
 astscf_component_add_files(logging-client IceLogger.cpp)
 astscf_component_add_files(logging-client OstreamLogger.cpp)
 astscf_component_add_files(logging-client IceConfigurator.h)
 astscf_component_add_files(logging-client ../../include/AsteriskSCF/logger.h)
 astscf_component_add_files(logging-client ../../include/AsteriskSCF/Logger/LogOut.h)
+astscf_component_add_files(logging-client ../../include/AsteriskSCF/Logger/LogConsts.h)
 astscf_component_add_files(logging-client ../../include/AsteriskSCF/Logger/IceLogger.h)
 astscf_component_add_files(logging-client ../../include/AsteriskSCF/Logger/Level.h)
-astscf_component_add_boost_libraries(logging-client thread date_time)
+astscf_component_add_files(logging-client ../../include/AsteriskSCF/Logger/LogFormatter.h)
+astscf_component_add_boost_libraries(logging-client thread date_time system)
 astscf_component_add_ice_libraries(logging-client IceStorm)
 astscf_component_add_slice_collection_libraries(logging-client ASTSCF)
 astscf_component_build_library(logging-client)
diff --git a/client/src/IceLogger.cpp b/client/src/IceLogger.cpp
index a72d48e..070c1b2 100644
--- a/client/src/IceLogger.cpp
+++ b/client/src/IceLogger.cpp
@@ -14,12 +14,16 @@
  * at the top of the source tree.
  */
 
+#include <boost/asio/ip/host_name.hpp>
+#include <boost/interprocess/detail/os_thread_functions.hpp>
+
 #include <IceStorm/IceStorm.h>
 
 #include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
 
 #include <AsteriskSCF/Logger/IceLogger.h>
 #include <AsteriskSCF/Logger/Level.h>
+#include <AsteriskSCF/Logger/LogConsts.h>
 
 using namespace AsteriskSCF::Core::Discovery::V1;
 using namespace AsteriskSCF::System::Logging;
@@ -30,9 +34,19 @@ void IceLogger::logs(const std::string& name, Level logLevel,
     bool logged = false;
     try
     {
+
+        std::string hostName = boost::asio::ip::host_name();
+
         if (mServer)
         {
-            mServer->logs(name, logLevel, message);
+            mServer->logs(name, 
+                          logLevel, 
+                          message, 
+                          hostName,
+                          (Ice::Long)boost::interprocess::detail::get_current_process_id(), 
+                          mComponentCategory,
+                          mComponentServiceName,
+                          mComponentId);
             logged = true;
         }
     }
@@ -55,10 +69,19 @@ void IceLogger::logs(const std::string& name, Level logLevel,
                 "!!! Unable to log to server.  Please check configuration and server status.\n"
                 "!!! Logging to stderr instead.\n";
         }
-        std::clog << name << ":" << logLevel << ":" << message << '\n';
+        std::clog << message << '\n';
     }
 }
 
+void IceLogger::setComponentInfo(const std::string& componentCategory, 
+                        const std::string& serviceName,
+                        const std::string& id)
+{
+    mComponentCategory = componentCategory;
+    mComponentServiceName = serviceName;
+    mComponentId = id;
+}
+
 IceUtil::Handle<ConfiguredIceLogger> ConfiguredIceLogger::create(
     const LoggingServerPrx& server)
 {
diff --git a/client/src/LogFormatter.cpp b/client/src/LogFormatter.cpp
new file mode 100644
index 0000000..f747772
--- /dev/null
+++ b/client/src/LogFormatter.cpp
@@ -0,0 +1,201 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/filesystem.hpp>
+
+#include <AsteriskSCF/logger.h>
+
+using namespace AsteriskSCF::System::Logging;
+using namespace std;
+
+LogFormatter::LogFormatter(const std::string& fmtStr) :
+    mFormat(fmtStr)
+{
+}
+
+LogFormatter::~LogFormatter()
+{
+}
+
+/**
+ * Builds a formatted string with some source code information in it.
+ */
+std::string AsteriskSCF::System::Logging::sourceInfoStr(const std::string& fmt, unsigned int line,
+                                                        const char* fcn, const char* file)
+{
+    std::string s(fmt);
+    std::size_t pos;
+    bool found = true;
+    
+    while (found)
+    {
+        found = false;
+        if ((pos=s.find("$l",0))!=std::string::npos)
+        {
+            s.replace(pos,2,boost::lexical_cast<std::string>(line));
+            found = true;
+        }
+        if ((pos=s.find("$f",0))!=std::string::npos)
+        {
+            s.replace(pos,2,boost::lexical_cast<std::string>(fcn));
+            found = true;
+        }
+        if ((pos=s.find("$sp",0))!=std::string::npos)
+        {
+            s.replace(pos,3,boost::lexical_cast<std::string>(file));
+            found = true;
+        }
+        if ((pos=s.find("$sf",0))!=std::string::npos)
+        {
+            boost::filesystem::path p(file);
+            s.replace(pos,3,boost::lexical_cast<std::string>(p.leaf()));
+            found = true;
+        }
+    }
+    return s;
+}
+
+void LogFormatter::setFormat(const std::string& fmtStr)
+{
+    boost::unique_lock<boost::shared_mutex> lock(mMutex);
+    mFormat = fmtStr;
+}
+
+std::string LogFormatter::getFormat()
+{
+    boost::shared_lock<boost::shared_mutex> lock(mMutex);
+
+    return mFormat;
+}
+
+std::string getFormattedTime(const boost::posix_time::ptime& t, const std::string& format)
+{
+    boost::posix_time::time_facet* outputFacet = new boost::posix_time::time_facet();
+
+    std::stringstream ss;
+    ss.imbue(std::locale(std::locale::classic(), outputFacet));
+    outputFacet->format(format.c_str());
+
+    ss << t;
+
+    return ss.str();
+}
+
+std::string getFormattedTime(const  boost::posix_time::ptime& t)
+{
+    std::stringstream ss;
+
+    ss << t;
+    return ss.str();
+}
+
+/**
+ * Formats a log string and returns it for output
+ */
+std::string LogFormatter::formatMessage(const std::string& message, const std::string& name, Level level,
+        const std::string& hostName, Ice::Long pid, 
+        const std::string& componentCategory, const std::string& serviceId, const std::string& instanceId) const
+{
+    std::string outStr;
+    std::size_t pos;
+    outStr = mFormat;
+
+    if ((pos=outStr.find("$t{",0)) != std::string::npos)
+    {
+        // Client timestamp (formatted). 
+        try
+        {
+            boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
+
+            std::size_t pos2 = outStr.find("}",pos+3);
+            if (pos2 != std::string::npos)
+            {
+                std::string userTimeFormat = outStr.substr(pos+3,pos2-3);
+                std::string nowStr = getFormattedTime(now, userTimeFormat);
+
+                outStr.replace(pos,pos+pos2+1,nowStr);
+            }
+        }
+        catch (...)
+        {
+           // Don't do anything to outStr, so the timestamp format specifier will show up
+           // in the output and signal to someone that the format is wrong
+        }
+    }
+    else if ((pos=outStr.find("$t",0)) != std::string::npos)
+    {
+        // Client timestamp (default formatting)
+        boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
+        string nowString = getFormattedTime(now);
+
+        outStr.replace(pos,2,nowString);
+    }
+
+    if ((pos=outStr.find("$n",0)) != std::string::npos)
+    {
+        // Logger name
+        outStr.replace(pos,2,name);
+    }
+
+    if ((pos=outStr.find("$l",0)) != std::string::npos)
+    {
+        // Priority / level
+        std::stringstream s("");
+
+        s << level;
+        outStr.replace(pos,2,s.str());
+    }
+
+    if ((pos=outStr.find("$h",0)) != std::string::npos)
+    {
+        // Client host name
+        if (hostName.size()==0)
+        {
+            outStr.replace(pos,2,"");
+        }
+        else outStr.replace(pos,2,hostName);
+    }
+
+    if ((pos=outStr.find("$p",0)) != std::string::npos)
+    {
+        // Process ID
+        outStr.replace(pos,2,boost::lexical_cast<std::string>(pid));
+    }
+
+    if ((pos=outStr.find("$C",0)) != std::string::npos)
+    {
+        outStr.replace(pos, 2, componentCategory);
+    }
+
+    if ((pos=outStr.find("$S",0)) != std::string::npos)
+    {
+         outStr.replace(pos, 2, serviceId);
+    }
+
+    if ((pos=outStr.find("$I",0)) != std::string::npos)
+    {
+         outStr.replace(pos, 2, instanceId);
+    }
+
+    if ((pos=outStr.find("$m",0)) != std::string::npos)
+    {
+        // Check for message specifier last so we don't modify the message itself
+        outStr.replace(pos,2,message);
+    }
+
+    return outStr;
+}
diff --git a/client/src/Logger.cpp b/client/src/Logger.cpp
index 99b651b..f06015a 100644
--- a/client/src/Logger.cpp
+++ b/client/src/Logger.cpp
@@ -16,29 +16,37 @@
 
 #include <cassert>
 #include <cstdio>
+#include <sstream>
+#include <iomanip>
+#include <cstdlib>
+#include <time.h>
+
+#include <boost/thread/thread.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 #include <AsteriskSCF/logger.h>
 
 using namespace AsteriskSCF::System::Logging;
 
-const int MESSAGE_SIZE = 120;
 
-LogBuf::LogBuf(LogOut& out, const std::string& name, Level logLevel) :
-    mOut(out), nName(name), mLogLevel(logLevel)
+LogBuf::LogBuf(LogOut& out, const std::string& name, Level level) :
+    mOut(out), mName(name), mLogLevel(level)
 {
 }
 
+
 // NOTE: The copy constructor below intentionally calls the default constructor of its
 // std::streambuf base, rather than calling the copy constructor. The copy constructor
 // of std::streambuf is private (so it cannot be called), but more importantly, the
 // std::streambuf base object has no useful state that needs to be copied when a
 // LogBuf is copied.
 LogBuf::LogBuf(const LogBuf& orig) :
-    std::streambuf(), mOut(orig.mOut), nName(orig.nName), mLogLevel(orig.mLogLevel)
+    std::streambuf(), mOut(orig.mOut), mName(orig.mName), mLogLevel(orig.mLogLevel)
 {
     mBuffer.str(orig.mBuffer.str());
 }
 
+
 LogBuf::~LogBuf()
 {
     if (!mBuffer.str().empty())
@@ -47,6 +55,7 @@ LogBuf::~LogBuf()
     }
 }
 
+
 int LogBuf::overflow(int c)
 {
     if (c == '\n' || c == traits_type::eof())
@@ -57,24 +66,25 @@ int LogBuf::overflow(int c)
     return mBuffer.sputc((char) c);
 }
 
+
 void LogBuf::sendBuffer()
 {
-    // logic looks a bit backwards, but that's in case out.logs()
+    // logic looks a bit backwards, but that's in case mOut.logs()
     // throws an exception, we still want to clear the buffer.
     const std::string& message = mBuffer.str();
     mBuffer.str("");
-    // send
-    mOut.logs(nName, mLogLevel, message);
+    mOut.logs(mName,mLogLevel,message);
 }
 
+
 Logger::LoggerImpl::LoggerImpl(const std::string& name, LogOut& out, Level logLevel) :
     mParent(), mName(name), mOut(&out), mLogLevel(logLevel), mInheritedLevel(false)
 {
 }
 
+
 Logger::LoggerImpl::LoggerImpl(const boost::shared_ptr<LoggerImpl>& parent, const std::string& name) :
-    mParent(parent), mName(name), mOut(parent->mOut), mLogLevel(Off),
-    mInheritedLevel(true)
+    mParent(parent), mName(name), mOut(parent->mOut), mLogLevel(Off), mInheritedLevel(true)
 {
     // parent ptr must be non-null
     assert(parent != 0);
@@ -86,29 +96,33 @@ Logger::LoggerImpl::~LoggerImpl()
 {
 }
 
+
 CondStream Logger::LoggerImpl::operator()(Level level) const
 {
-    return CondStream(*mOut, mName, level, isEnabledFor(level));
+    return CondStream(*mOut,mName,level,isEnabledFor(level));
 }
 
+
 void Logger::LoggerImpl::logs(Level level, const std::string& message) const
 {
     if (isEnabledFor(level))
     {
-        mOut->logs(mName, level, message);
+        mOut->logs(mName,level,message);
     }
 }
 
+
 void Logger::LoggerImpl::vlogf(Level level, char const *fmt, va_list ap) const
 {
     if (isEnabledFor(level))
     {
         char message[MESSAGE_SIZE];
         vsnprintf(message, sizeof(message), fmt, ap);
-        mOut->logs(mName, level, message);
+        mOut->logs(mName,level,std::string(message));
     }
 }
 
+
 void Logger::LoggerImpl::setOutput(LogOut& out)
 {
     this->mOut = &out;
@@ -124,21 +138,23 @@ void Logger::LoggerImpl::setOutput(LogOut& out)
 
 void Logger::LoggerImpl::setLevel(Level logLevel)
 {
-    boost::unique_lock<boost::shared_mutex> lock(mLevelMutex);
+    boost::unique_lock<boost::shared_mutex> lock(mInheritedMutex);
     mLogLevel = logLevel;
     mInheritedLevel = false;
 }
 
+
 void Logger::LoggerImpl::unsetLevel()
 {
-    boost::unique_lock<boost::shared_mutex> lock(mLevelMutex);
+    boost::unique_lock<boost::shared_mutex> lock(mInheritedMutex);
     mInheritedLevel = true;
     mLogLevel = Off;
 }
 
+
 Level Logger::LoggerImpl::getEffectiveLevel() const
 {
-    boost::shared_lock<boost::shared_mutex> lock(mLevelMutex);
+    boost::shared_lock<boost::shared_mutex> lock(mInheritedMutex);
     // If parent is null, either we've never had a parent, or that
     // parent has been destroyed.
     boost::shared_ptr<const LoggerImpl> parent = mParent.lock();
@@ -153,6 +169,7 @@ Level Logger::LoggerImpl::getEffectiveLevel() const
     }
 }
 
+
 Logger Logger::LoggerImpl::getChild(const boost::shared_ptr<LoggerImpl>& self,
     const std::string& childName)
 {
@@ -169,6 +186,7 @@ Logger Logger::LoggerImpl::getChild(const boost::shared_ptr<LoggerImpl>& self,
     return Logger(child);
 }
 
+
 std::vector<Logger> Logger::LoggerImpl::getChildren() const
 {
     std::vector<Logger> r;
@@ -181,4 +199,3 @@ std::vector<Logger> Logger::LoggerImpl::getChildren() const
     }
     return r;
 }
-
diff --git a/client/src/LoggerFactory.cpp b/client/src/LoggerFactory.cpp
index 3ad3c42..0013c75 100644
--- a/client/src/LoggerFactory.cpp
+++ b/client/src/LoggerFactory.cpp
@@ -14,6 +14,7 @@
  * at the top of the source tree.
  */
 
+
 #include <string>
 #include <map>
 #include <vector>
@@ -35,6 +36,7 @@ namespace
 boost::once_flag oneFactory = BOOST_ONCE_INIT;
 LoggerFactory *loggerFactory = 0;
 
+
 void initLoggerFactory()
 {
     static boost::shared_ptr<LogOut> out = buildOstreamLogger(std::cout);
diff --git a/client/src/OstreamLogger.cpp b/client/src/OstreamLogger.cpp
index d3b35c6..9d3aa0d 100644
--- a/client/src/OstreamLogger.cpp
+++ b/client/src/OstreamLogger.cpp
@@ -14,7 +14,13 @@
  * at the top of the source tree.
  */
 
+#include <boost/shared_ptr.hpp>
+#include <boost/asio/ip/host_name.hpp>
+
+#include <boost/interprocess/detail/os_thread_functions.hpp>
+
 #include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/Logger/LogFormatter.h>
 
 using namespace AsteriskSCF::System::Logging;
 
@@ -24,25 +30,50 @@ namespace
 class OstreamLogger : public LogOut
 {
 public:
-    OstreamLogger(std::ostream& out) :
-        mOut(out)
+    OstreamLogger(std::ostream& out, const std::string& fmtStr = DefaultLogFormat) :
+        mOut(out), mFormatter(fmtStr)
     {
+        mProcessId = (Ice::Long)boost::interprocess::detail::get_current_process_id();
 
+        mHostName = boost::asio::ip::host_name();
     }
 
-    void logs(const std::string& name, Level logLevel,
+    void logs(const std::string& name, Level level,
         const std::string& message)
     {
-        mOut << name << ":" << logLevel << ":" << message << '\n';
+        boost::unique_lock<boost::mutex> lock(mMutex);
+        mOut << mFormatter.formatMessage(message,name,level,mHostName,mProcessId,mComponentCategory,mServiceId,mComponentId) << '\n';
+    }
+
+    void setComponentInfo(const std::string& componentCategory, 
+                            const std::string& serviceId,
+                            const std::string& id)
+    {
+        mComponentCategory = componentCategory;
+        mServiceId = serviceId;
+        mComponentId = id;
     }
 
 private:
     std::ostream& mOut;
+    boost::mutex mMutex;
+
+    std::string mComponentCategory;
+    std::string mServiceId;
+    std::string mComponentId;
+    std::string mHostName;
+    Ice::Long mProcessId;
+
+    /**
+     * Current formatter for this logger
+     */
+    LogFormatter mFormatter;
 };
 
 }
 
-boost::shared_ptr<LogOut> AsteriskSCF::System::Logging::buildOstreamLogger(std::ostream& out)
+boost::shared_ptr<LogOut> AsteriskSCF::System::Logging::buildOstreamLogger(std::ostream& out,
+        const std::string& fmtStr)
 {
-    return boost::shared_ptr<LogOut>(new OstreamLogger(out));
+    return boost::shared_ptr<LogOut>(new OstreamLogger(out,fmtStr));
 }
diff --git a/client/test/CMakeLists.txt b/client/test/CMakeLists.txt
index 9e4fd16..894d7d0 100644
--- a/client/test/CMakeLists.txt
+++ b/client/test/CMakeLists.txt
@@ -6,6 +6,7 @@ astscf_component_add_files(logging-client-test LoggerFactory-test.cpp)
 astscf_component_add_files(logging-client-test LogBuf-test.cpp)
 astscf_component_add_files(logging-client-test IceConfigurator-test.cpp)
 astscf_component_add_files(logging-client-test client-test.cpp)
+astscf_component_add_files(logging-client-test ExpectedLogOut.h)
 astscf_component_add_boost_libraries(logging-client-test unit_test_framework)
 astscf_component_add_slice_collection_libraries(logging-client-test ASTSCF)
 astscf_component_build_standalone(logging-client-test)
diff --git a/client/test/ExpectedLogOut.h b/client/test/ExpectedLogOut.h
index 5617129..78ef6f9 100644
--- a/client/test/ExpectedLogOut.h
+++ b/client/test/ExpectedLogOut.h
@@ -8,6 +8,8 @@
 
 #pragma once
 
+#include <boost/test/unit_test.hpp>
+
 #include <AsteriskSCF/logger.h>
 
 namespace AsteriskSCF
@@ -20,27 +22,38 @@ namespace Logging
 /**
  * Mock class to check the output that makes it to a LogOut interface.
  */
-class ExpectedLogOut : public LogOut
+class ExpectedLogOut
 {
 public:
-    ExpectedLogOut(const std::string& expected) :
-        mExpected(expected)
+    ExpectedLogOut(const std::string& expected, const std::string& fmtStr = DefaultLogFormat) :
+        mExpected(expected), mLogOut(buildOstreamLogger(mActual,fmtStr))
     {
     }
 
-    void logs(const std::string& name, Level logLevel,
-        const std::string& message)
+    void check()
     {
-        mActual << name << ":" << logLevel << ":" << message << '\n';
+        std::string actual = mActual.str();
+        BOOST_CHECK(0 == actual.compare(0, mExpected.length(), mExpected));
     }
 
-    void check()
+    /** 
+     * @param less Shorten the length to compare by this amount. 
+     * (Time strings won't match the last few digits.)
+     */
+    void check(int less)
+    {
+        std::string actual = mActual.str();
+        BOOST_CHECK(0 == actual.compare(0, (mExpected.length() - less), mExpected, 0, (mExpected.length() - less)));
+    }
+
+    boost::shared_ptr<LogOut> operator()() 
     {
-        BOOST_CHECK_EQUAL(mExpected, mActual.str());
+        return mLogOut;
     }
 
 private:
     std::string mExpected;
+    boost::shared_ptr<LogOut> mLogOut;
     std::stringstream mActual;
 };
 
diff --git a/client/test/IceConfigurator-test.cpp b/client/test/IceConfigurator-test.cpp
index 5c07dd4..5b6988a 100644
--- a/client/test/IceConfigurator-test.cpp
+++ b/client/test/IceConfigurator-test.cpp
@@ -37,7 +37,7 @@ BOOST_AUTO_TEST_SUITE(IceConfiguratorTest)
 BOOST_AUTO_TEST_CASE(test_simple)
 {
     ExpectedLogOut out("");
-    LoggerFactory factory(out);
+    LoggerFactory factory(*out());
     IceConfigurator uut(factory);
 
     Configuration cfg;
@@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(test_simple)
 BOOST_AUTO_TEST_CASE(test_reset)
 {
     ExpectedLogOut out("");
-    LoggerFactory factory(out);
+    LoggerFactory factory(*out());
     IceConfigurator uut(factory);
 
     Configuration cfg;
diff --git a/client/test/LogBuf-test.cpp b/client/test/LogBuf-test.cpp
index 845f5f6..fbdbc60 100644
--- a/client/test/LogBuf-test.cpp
+++ b/client/test/LogBuf-test.cpp
@@ -24,10 +24,12 @@ 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);
+    boost::shared_ptr<LogFormatter> formatter(new LogFormatter(&out));
+    LogBuf uut(formatter, "src", Info);
     std::ostream stream(&uut);
 
     stream << "testing" << '\n';
@@ -37,11 +39,13 @@ BOOST_AUTO_TEST_CASE(test_stream)
 BOOST_AUTO_TEST_CASE(test_stream_format)
 {
     ExpectedLogOut out("src:Debug:debug f00d\n");
-    LogBuf buf(out, "src", Debug);
+    boost::shared_ptr<LogFormatter> formatter(new LogFormatter(&out));
+    LogBuf buf(formatter, "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 0964c6f..380a399 100644
--- a/client/test/Logger-test.cpp
+++ b/client/test/Logger-test.cpp
@@ -14,11 +14,17 @@
  * at the top of the source tree.
  */
 
+#include <sstream>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/interprocess/detail/os_thread_functions.hpp>
 #include <boost/test/unit_test.hpp>
+#include <boost/asio/ip/host_name.hpp>
 
 #include <AsteriskSCF/logger.h>
 #include "ExpectedLogOut.h"
 
+using namespace std;
 using namespace AsteriskSCF::System::Logging;
 
 BOOST_AUTO_TEST_SUITE( LoggerTest )
@@ -26,89 +32,166 @@ BOOST_AUTO_TEST_SUITE( LoggerTest )
 BOOST_AUTO_TEST_CASE( test_log )
 {
     ExpectedLogOut out("src:Critical:Critical Message\n");
-    Logger uut("src", out, Debug);
+    Logger uut("src", *out(), Debug);
 
     uut.logs(Critical, "Critical Message");
     out.check();
 }
 
+
+BOOST_AUTO_TEST_CASE( test_log_srcinfo )
+{
+    ExpectedLogOut out("src:Debug:Logger-test.cpp: Debug Message\n");
+    Logger uut("src", *out(), Debug);
+
+    uut.logs(Debug, SRCINFO("$sf: ") + "Debug Message");
+    out.check();
+}
+
+
 BOOST_AUTO_TEST_CASE( test_logf )
 {
     ExpectedLogOut out("src:Critical:Critical message f00d\n");
-    Logger uut("src", out, Debug);
+    Logger uut("src", *out(), Debug);
 
     uut.logf(Critical, "Critical message %04x", 61453);
     out.check();
 }
 
+
 BOOST_AUTO_TEST_CASE( test_same_level )
 {
     ExpectedLogOut out("src:Debug:debug\n");
-    Logger uut("src", out, Debug);
+    Logger uut("src", *out(), Debug);
 
     uut.logs(Debug, "debug");
     out.check();
 }
 
+
 BOOST_AUTO_TEST_CASE( test_log_squelched )
 {
     ExpectedLogOut out("");
-    Logger uut("src", out, Info);
+    Logger uut("src", *out(), Info);
 
     uut.logs(Debug, "debug\n");
     out.check();
 }
 
+
 BOOST_AUTO_TEST_CASE(test_stream_on)
 {
     ExpectedLogOut out("src:Debug:debug\n");
-    Logger uut("src", out, Debug);
+    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);
+    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);
+    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);
+
+    std::string hostName = boost::asio::ip::host_name();
+
+    BOOST_REQUIRE(hostName.length() != 0); 
+    ExpectedLogOut out("Debug:src:" + hostName + ": debug f00d\n",
+                       "$l:$n:$h: $m");
+
+    Logger uut("src", *out(), Debug);
 
     uut(Debug) << "debug " << std::hex << 61453 << '\n';
     out.check();
 }
 
+std::string getFormattedTime(const boost::posix_time::ptime& t, const std::string& format)
+{
+    boost::posix_time::time_facet* outputFacet = new boost::posix_time::time_facet();
+
+    std::stringstream ss;
+    ss.imbue(std::locale(std::locale::classic(), outputFacet));
+    outputFacet->format(format.c_str());
+
+    ss <<  t;
+
+    return ss.str();
+}
+
+// Default format
+std::string getFormattedTime(const  boost::posix_time::ptime& t)
+{
+    std::stringstream ss;
+
+    ss << t;
+    return ss.str();
+}
+
+BOOST_AUTO_TEST_CASE(test_stream_timestamp)
+{
+    boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
+
+    Ice::Long pid = (Ice::Long)boost::interprocess::detail::get_current_process_id();
+    std::string nowStr = getFormattedTime(now);
+
+    ExpectedLogOut out(boost::lexical_cast<std::string>(pid) + ":src:Debug:TimeStamp test:Logger-test.cpp : " + nowStr,
+        "$p:$n:$l:$m : $t");
+    Logger uut("src", *out(), Debug);
+
+    uut(Debug) << "TimeStamp test:" << SRCINFO("$sf") << '\n';
+
+    out.check(6);
+}
+
+BOOST_AUTO_TEST_CASE(test_stream_timestamp_formatted)
+{
+    boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
+
+    std::string nowStr = getFormattedTime(now, "%x %H:%M:%S%p");
+
+    ExpectedLogOut out("src:Debug:TimeStamp format test " + nowStr,
+                       "$n:$l:$m $t{%x %H:%M:%S%p}");
+    Logger uut("src", *out(), Debug);
+
+    uut(Debug) << "TimeStamp format test" << '\n';
+    out.check(6);
+}
+
+
 BOOST_AUTO_TEST_CASE(test_stream_lots)
 {
     ExpectedLogOut out("src:Debug:debug\nsrc:Info:info\n");
-    Logger uut("src", out, Debug);
+    Logger uut("src", *out(), Debug);
 
     uut(Debug) << "debug";
     uut(Info) << "info";
     out.check();
 }
 
+
 BOOST_AUTO_TEST_CASE(test_endl)
 {
     ExpectedLogOut out("src:Info:testing\n");
-    Logger uut("src", out, Info);
+    Logger uut("src", *out(), Info);
 
     uut(Info) << "testing" << std::endl;
     out.check();
diff --git a/client/test/LoggerFactory-test.cpp b/client/test/LoggerFactory-test.cpp
index ea98bcc..1eebc8c 100644
--- a/client/test/LoggerFactory-test.cpp
+++ b/client/test/LoggerFactory-test.cpp
@@ -60,12 +60,12 @@ BOOST_AUTO_TEST_CASE(testChangeLogOut)
     ExpectedLogOut out1("src:Critical:Critical Message\n");
     ExpectedLogOut out2("src:Debug:Debug Message\n");
 
-    Logger uut("src", out1, Debug);
+    Logger uut("src", *out1(), Debug);
 
     uut.logs(Critical, "Critical Message");
     out1.check();
 
-    uut.setOutput(out2);
+    uut.setOutput(*out2());
     uut.logs(Debug, "Debug Message");
     out1.check();
     out2.check();
diff --git a/include/AsteriskSCF/Logger/IceLogger.h b/include/AsteriskSCF/Logger/IceLogger.h
index 258a718..487b834 100644
--- a/include/AsteriskSCF/Logger/IceLogger.h
+++ b/include/AsteriskSCF/Logger/IceLogger.h
@@ -31,13 +31,18 @@ public:
 
     void logs(const std::string& name, Level logLevel,
         const std::string& message);
-
+    void setComponentInfo(const std::string& componentCategory, 
+                          const std::string& serviceName,
+                          const std::string& id);
     const LoggingServerPrx& getServer() const { return mServer; }
     void setServer(const LoggingServerPrx& server) { this->mServer = server; }
 
 private:
     LoggingServerPrx mServer;
     bool mHasPrintedNoServerNotice;
+    std::string mComponentCategory;
+    std::string mComponentServiceName;
+    std::string mComponentId;
 };
 
 /**
diff --git a/include/AsteriskSCF/Logger/LogOut.h b/include/AsteriskSCF/Logger/LogConsts.h
similarity index 71%
copy from include/AsteriskSCF/Logger/LogOut.h
copy to include/AsteriskSCF/Logger/LogConsts.h
index 4a93165..d4eb1db 100644
--- a/include/AsteriskSCF/Logger/LogOut.h
+++ b/include/AsteriskSCF/Logger/LogConsts.h
@@ -28,16 +28,20 @@ namespace Logging
 {
 
 /**
- * Interface abstracting how the logs actually get written.
+ * Constants used in the logger client
  */
-class LogOut
-{
-public:
-    ASTSCF_DLL_EXPORT virtual ~LogOut();
-    ASTSCF_DLL_EXPORT virtual void logs(const std::string& name, Level logLevel,
-        const std::string& message) = 0;
-};
 
+const int MESSAGE_SIZE = 512;
+
+const int TIMESTAMP_SIZE = 64;
+
+const int HOSTNAME_SIZE = 128;
+
+const std::string DefaultLogFormat = "$n:$l:$m";
+
+const std::string TimestampFormat = "%x %X";
+
+const AsteriskSCF::System::Logging::Level DefaultLoggingLevel = Debug;
 
 } // Logging
 } // System
diff --git a/include/AsteriskSCF/Logger/LogFormatter.h b/include/AsteriskSCF/Logger/LogFormatter.h
new file mode 100644
index 0000000..7b6dd69
--- /dev/null
+++ b/include/AsteriskSCF/Logger/LogFormatter.h
@@ -0,0 +1,104 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+#pragma once
+
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/current_function.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#include <AsteriskSCF/Logger/LogConsts.h>
+#include <AsteriskSCF/Logger/Level.h>
+
+/**
+ * Macro for getting some source information into a log message. 
+ * @param S formatting string for macro, can have the following specifiers:
+ * $l  -  current line number
+ * $f  -  current function name
+ * $sf -  source file name
+ * $sp -  source file name, including path
+ */
+#define SRCINFO(S) \
+      AsteriskSCF::System::Logging::sourceInfoStr(boost::lexical_cast<std::string>(S), \
+                                                  __LINE__, BOOST_CURRENT_FUNCTION, __FILE__)
+
+namespace AsteriskSCF
+{
+namespace System
+{
+namespace Logging
+{
+
+/**
+ * Class used to format log messages. The LogFormatter uses a format string to 
+ * describe what a formatted log message should look like.
+ *
+ * The format string is composed of format parameters and other text, much like
+ * the printf statement. Valid format parameters are:
+ * 
+ * $n - the name of the logger
+ * $l - the level of the message being logged
+ * $h - the client host name
+ * $t - current time, can be further formatted with additional specifiers following the 
+ *      boost::posix_time::time_facet format, which is similar to the strftime() format. 
+ *      The additional specifiers should be in a set of curly braces, 
+ *      like: $t{%x %X} would format the time into a date/time string. If no additional
+ *      format specifiers are given (ie, just $t), the system uses the default
+ *      time format.
+ * $p - current process id
+ * $d - delta in time between this message and the last one (shows as seconds.milliseconds)
+ * $m - the message to log. You probably always want this one in your format string.
+ * 
+ * $C - component category. This is part of the Service Locator params for the Component 
+ *      Service for the component performing the logging. 
+ * $S - service name. This is part of the Service Locator params for the Component 
+ *      Service for the component performing the logging. 
+ * $I - component instance id. This is part of the Service Locator params for the Component 
+ *      Service for the component performing the logging. 
+ * $L - The service locator params triad with commas between items. Same as specifying: "$C,$S,$I" 
+ */
+
+class LogFormatter
+{
+public:
+    LogFormatter(const std::string& fmtStr = DefaultLogFormat);
+    ~LogFormatter();
+    void setFormat(const std::string& fmtStr);
+    std::string getFormat();
+    std::string formatMessage(const std::string& message, const std::string& name, Level level, 
+        const std::string& hostName, Ice::Long pid, 
+        const std::string& componentCategory, const std::string& serviceId, const std::string& componentId) const;
+private:
+    std::string mFormat;
+    boost::shared_mutex mMutex;
+};
+
+/**
+ * Returns a semi-formatted string containing some source code
+ * information (line, function, file)
+ *
+ * See description of SRCINFO macro for formatting options.
+ */
+ASTSCF_DLL_EXPORT std::string sourceInfoStr(const std::string& fmt, unsigned int line, 
+                                                     const char* fcn, const char* file);
+
+} // Logging
+} // System
+} // AsteriskSCF
diff --git a/include/AsteriskSCF/Logger/LogOut.h b/include/AsteriskSCF/Logger/LogOut.h
index 4a93165..78ee517 100644
--- a/include/AsteriskSCF/Logger/LogOut.h
+++ b/include/AsteriskSCF/Logger/LogOut.h
@@ -29,6 +29,8 @@ namespace Logging
 
 /**
  * Interface abstracting how the logs actually get written.
+ *
+ * NOTE: it is your responsibility to make sure your LogOut implementation is threadsafe
  */
 class LogOut
 {
@@ -36,6 +38,10 @@ public:
     ASTSCF_DLL_EXPORT virtual ~LogOut();
     ASTSCF_DLL_EXPORT virtual void logs(const std::string& name, Level logLevel,
         const std::string& message) = 0;
+    ASTSCF_DLL_EXPORT virtual void setComponentInfo(
+        const std::string& componentCategory, 
+        const std::string& serviceName,
+        const std::string& id) = 0;
 };
 
 
diff --git a/include/AsteriskSCF/logger.h b/include/AsteriskSCF/logger.h
index 800c7d9..ad790fc 100644
--- a/include/AsteriskSCF/logger.h
+++ b/include/AsteriskSCF/logger.h
@@ -18,16 +18,20 @@
 
 #include <ostream>
 #include <cstdarg>
+#include <string>
 
 #include <boost/shared_ptr.hpp>
 #include <boost/thread/locks.hpp>
 #include <boost/thread/mutex.hpp>
 #include <boost/thread/shared_mutex.hpp>
 #include <boost/weak_ptr.hpp>
+#include <boost/lexical_cast.hpp>
 
 #include <AsteriskSCF/System/Logger/LoggerIf.h>
 #include <AsteriskSCF/Logger/Level.h>
 #include <AsteriskSCF/Logger/LogOut.h>
+#include <AsteriskSCF/Logger/LogConsts.h>
+#include <AsteriskSCF/Logger/LogFormatter.h>
 
 namespace AsteriskSCF
 {
@@ -60,11 +64,11 @@ protected:
 private:
     std::stringbuf mBuffer;
     LogOut& mOut;
-    const std::string nName;
-    const Level mLogLevel;
+    std::string mName;
+    Level mLogLevel;
 
     /**
-     * Sends the current buffer to out and clears it.
+     * Sends the current buffer to the formatter and clears it.
      */
     void sendBuffer();
 };
@@ -76,9 +80,9 @@ private:
 class CondStream
 {
 public:
-    CondStream(LogOut& out, const std::string& name, Level logLevel,
-        bool enabled) :
-        mBuf(out, name, logLevel), mStream(&mBuf), mEnabled(enabled)
+    CondStream(LogOut& out, const std::string& name, Level level, 
+            bool enabled) :
+        mBuf(out,name,level), mStream(&mBuf), mEnabled(enabled)
     {
     }
 
@@ -157,11 +161,11 @@ private:
 public:
     /** Construct a Logger for an existing implementation */
     Logger(const boost::shared_ptr<LoggerImpl>& impl);
+
     /**
      * Construct a root Logger.
      */
     Logger(const std::string& name, LogOut& out, Level logLevel = Debug);
-
     /**
      * If true, this Logger would log messages of the given Level.
      *
@@ -169,7 +173,6 @@ public:
      * @return true if enabled for given level.
      */
     bool isEnabledFor(Level level) const;
-
     /**
      * Ostream style logging.
      *
@@ -177,58 +180,47 @@ public:
      * @return LogStream that logs at the given level.
      */
     CondStream operator()(Level level) const;
-
     /**
      * Log a single message.
      */
-    void logs(Level level, const std::string& message) const;
-
+    void logs(Level level, const std::string& message);
     /**
      * Log a single printf-formatted message.
      */
 #ifdef __GNUC__
     __attribute__((format(printf, 3, 4)))
 #endif
-    void logf(Level level, char const *fmt, ...) const;
-
+    void logf(Level level, char const *fmt, ...);
     /**
      * Log a single vprintf-formatted message.
      */
 #ifdef __GNUC__
     __attribute__((format(printf, 3, 0)))
 #endif
-    void vlogf(Level level, char const *fmt, va_list ap) const;
-
+    void vlogf(Level level, char const *fmt, va_list ap);
     Logger getChild(const std::string& childName);
-
     std::vector<Logger> getChildren() const;
-
     const std::string& getName() const;
-
     LogOut& getOutput() const;
-
     void setOutput(LogOut& out);
-
     /**
-     * Set's the current logLevel.  Until unsetLevel() is called, we are no
+     * Sets the current logLevel.  Until unsetLevel() is called, we are no
      * longer affected by changes to our parent's log level.
      */
     void setLevel(Level logLevel);
-
     /**
-     * Changes our logLevel to now inherit from out parent.
+     * Changes our logLevel to now inherit from our parent.
      */
     void unsetLevel();
-
     /**
      * Returns the effective level of this Logger.
      */
     Level getEffectiveLevel() const;
-
 private:
     boost::shared_ptr<LoggerImpl> mImpl;
 };
 
+
 class Logger::LoggerImpl
 {
 public:
@@ -237,7 +229,6 @@ public:
      */
     ASTSCF_DLL_EXPORT LoggerImpl(const std::string& name, LogOut& out,
         Level logLevel = Debug);
-
     /**
      * Construct a child Logger.
      */
@@ -256,7 +247,6 @@ public:
     {
         return level >= getEffectiveLevel();
     }
-
     /**
      * Ostream style logging.
      *
@@ -295,7 +285,7 @@ public:
     ASTSCF_DLL_EXPORT void setOutput(LogOut& out);
 
     /**
-     * Set's the current logLevel.  Until unsetLevel() is called, we are no
+     * Sets the current logLevel.  Until unsetLevel() is called, we are no
      * longer affected by changes to our parent's log level.
      */
     ASTSCF_DLL_EXPORT void setLevel(Level logLevel);
@@ -335,7 +325,6 @@ private:
      * Map of children.  The key is the next final node in that child's name.
      */
     Children mChildren;
-
     /**
      * Name of this logger, in dotted-notation.
      */
@@ -344,22 +333,22 @@ private:
      * Output for log messages.
      */
     LogOut *mOut;
-
     /**
-     * Mutex for accessing mLogLevel and mInheritedLevel.  It's a shared_mutext
+     * Mutex for accessing mLogLevel and mInherited.  It's a shared_mutex
      * to reduce read contention on the mutex.
      */
-    mutable boost::shared_mutex mLevelMutex;
+    mutable boost::shared_mutex mInheritedMutex;
     /**
      * Current level of this Logger.  Only applicable if inheritedLevel == false.
      */
     Level mLogLevel;
     /**
-     * If true, then our effectiveLevel == parent->effectiveLevel.
+     * If true, then our effectiveLevel == parent->effectiveLevel 
      */
     bool mInheritedLevel;
 };
 
+
 // since these are all simple delegates to LoggerImpl, inline them
 
 inline Logger::Logger(const boost::shared_ptr<LoggerImpl>& impl) :
@@ -367,24 +356,32 @@ inline Logger::Logger(const boost::shared_ptr<LoggerImpl>& impl) :
 {
 }
 
+
 inline Logger::Logger(const std::string& name, LogOut& out, Level logLevel) :
     mImpl(new LoggerImpl(name, out, logLevel))
 {
 }
 
+
 inline bool Logger::isEnabledFor(Level level) const
 {
     return mImpl->isEnabledFor(level);
 }
+
+
 inline CondStream Logger::operator()(Level level) const
 {
     return (*mImpl)(level);
 }
-inline void Logger::logs(Level level, const std::string& message) const
+
+
+inline void Logger::logs(Level level, const std::string& message)
 {
     mImpl->logs(level, message);
 }
-inline void Logger::logf(Level level, char const *fmt, ...) const
+
+
+inline void Logger::logf(Level level, char const *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
@@ -399,43 +396,62 @@ inline void Logger::logf(Level level, char const *fmt, ...) const
     }
     va_end(ap);
 }
-inline void Logger::vlogf(Level level, char const *fmt, va_list ap) const
+
+
+inline void Logger::vlogf(Level level, char const *fmt, va_list ap)
 {
     mImpl->vlogf(level, fmt, ap);
 }
+
+
 inline Logger Logger::getChild(const std::string& childName)
 {
     return mImpl->getChild(mImpl, childName);
 }
+
+
 inline std::vector<Logger> Logger::getChildren() const
 {
     return mImpl->getChildren();
 }
+
+
 inline const std::string& Logger::getName() const
 {
     return mImpl->getName();
 }
+
+
 inline LogOut& Logger::getOutput() const
 {
     return mImpl->getOutput();
 }
+
+
 inline void Logger::setOutput(LogOut& out)
 {
     mImpl->setOutput(out);
 }
+
+
 inline void Logger::setLevel(Level logLevel)
 {
     mImpl->setLevel(logLevel);
 }
+
+
 inline void Logger::unsetLevel()
 {
     mImpl->unsetLevel();
 }
+
+
 inline Level Logger::getEffectiveLevel() const
 {
     return mImpl->getEffectiveLevel();
 }
 
+
 /**
  * Main entry point into the Logger system.
  */
@@ -468,7 +484,7 @@ private:
     static void accumulateLoggerNames(Logger logger, std::vector<std::string>& out);
 };
 
-ASTSCF_DLL_EXPORT boost::shared_ptr<LogOut> buildOstreamLogger(std::ostream& out);
+ASTSCF_DLL_EXPORT boost::shared_ptr<LogOut> buildOstreamLogger(std::ostream& out, const std::string& FmtStr = DefaultLogFormat);
 
 /**
  * Returns the default configured LoggerFactory.
diff --git a/server/config/testloggingserver.conf b/server/config/testloggingserver.conf
index 1c3d132..537b754 100644
--- a/server/config/testloggingserver.conf
+++ b/server/config/testloggingserver.conf
@@ -1,11 +1,51 @@
 IceBox.InheritProperties=1
 
+IceBox.Service.ServiceDiscovery=service_locator:create
+
 IceBox.Service.Logger=logging-service:createLoggingService
 IceBox.Service.LoggerTest=LoggingConfigurationTest:create
 
-IceBox.LoadOrder=Logger,LoggerTest
+IceBox.LoadOrder=ServiceDiscovery,Logger,LoggerTest
 
 AsteriskSCF.LoggingService.Endpoints=tcp -p 31337
-Logger.Proxy=LoggerConfigurationService:tcp -p 31337
+LoggerConfiguration.Proxy=LoggerConfigurationService:tcp -p 31337
+
+# A proxy to the service locator management service
+LocatorServiceManagement.Proxy=LocatorServiceManagement:tcp -p 4422
+ServiceLocatorManagementAdapter.Endpoints=tcp -p 4422
+ServiceLocatorAdapter.Endpoints=tcp -p 4411
+LocatorService.Proxy=LocatorService:tcp -p 4411
+ServiceLocatorLocalAdapter.Endpoints=tcp -p 4412
+
+# Test endpoints for IceStorm
+TopicManager.Proxy=AsteriskSCFIceStorm/TopicManager:default -p 10000
+
+AsteriskSCFIceStorm.InstanceName=AsteriskSCFIceStorm
+#
+# This property defines the endpoints on which the IceStorm
+# TopicManager listens.
+#
+AsteriskSCFIceStorm.TopicManager.Endpoints=default -p 10000
+
+#
+# This property defines the endpoints on which the topic
+# publisher objects listen. If you want to federate
+# IceStorm instances this must run on a fixed port (or use
+# IceGrid).
+#
+AsteriskSCFIceStorm.Publish.Endpoints=tcp -p 10001:udp -p 10001
+
+#
+# TopicManager Tracing
+#
+# 0 = no tracing
+# 1 = trace topic creation, subscription, unsubscription
+# 2 = like 1, but with more detailed subscription information
+#
+AsteriskSCFIceStorm.Trace.TopicManager=2
+AsteriskSCFIceStorm.Transient=1
+
+#
+AsteriskSCFIceStorm.Flush.Timeout=2000
 
 LoggerTestAdapter.Endpoints=default
diff --git a/server/src/CMakeLists.txt b/server/src/CMakeLists.txt
index cba9221..622a1a8 100644
--- a/server/src/CMakeLists.txt
+++ b/server/src/CMakeLists.txt
@@ -12,12 +12,12 @@ astscf_component_add_files(logging-service-lib FileChainedLogOut.h)
 astscf_component_add_files(logging-service-lib OstreamChainedLogOut.h)
 astscf_component_add_files(logging-service-lib LoggingServer.h)
 astscf_component_add_files(logging-service-lib Configuration.h)
+astscf_component_add_files(logging-service-lib ../../client/src/LogFormatter.cpp)
 astscf_component_add_slices(logging-service-lib PROJECT AsteriskSCF/Configuration/LoggingService/LoggingConfigurationIf.ice)
-astscf_component_add_boost_libraries(logging-service-lib core)
+astscf_component_add_boost_libraries(logging-service-lib core thread date_time system)
 astscf_component_add_ice_libraries(logging-service-lib IceStorm)
 astscf_component_add_slice_collection_libraries(logging-service-lib ASTSCF)
 astscf_component_build_library(logging-service-lib STATIC)
-target_link_libraries(logging-service-lib)
 
 # This lib is compiled into a .so, so it needs -fPIC set
 if(CMAKE_COMPILER_IS_GNUCXX)
diff --git a/server/src/ChainedLogOut.cpp b/server/src/ChainedLogOut.cpp
index 65c2166..5870602 100644
--- a/server/src/ChainedLogOut.cpp
+++ b/server/src/ChainedLogOut.cpp
@@ -21,22 +21,6 @@
 
 using namespace AsteriskSCF::System::Logging;
 
-namespace
-{
-
-/**
- * Current time, as formatted string.
- */
-std::string getCurrentTime()
-{
-    char timeBuf[24];
-    std::time_t now = std::time(0);
-    std::strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S %Z", std::localtime(&now));
-    return timeBuf;
-}
-
-} // namespace
-
 ChainedLogOut::~ChainedLogOut()
 {
     // no-op
@@ -67,10 +51,7 @@ std::ostream& ChainedLogOut::logs(std::ostream& out, const std::string& name,
     }
     std::string lastname = name.substr(nameStart);
     {
-        std::ostream::fmtflags flags = out.flags();
-        out << getCurrentTime() << ' ' << std::setw(9) << logLevel << ' '
-            << std::setw(9) << std::left << lastname << ' ' << message << std::endl;
-        out.flags(flags);
+        out << message << std::endl;
     }
     return out;
 
diff --git a/server/src/Configuration.cpp b/server/src/Configuration.cpp
index faba577..463b5dd 100644
--- a/server/src/Configuration.cpp
+++ b/server/src/Configuration.cpp
@@ -14,6 +14,7 @@
  * at the top of the source tree.
  */
 
+#include <AsteriskSCF/Logger/LogConsts.h>
 #include "Configuration.h"
 #include "FileChainedLogOut.h"
 
@@ -40,7 +41,6 @@ public:
     }
     ~FileItemI()
     {
-        mServer->removeLogOut(mOut);
     }
     LoggingServerIPtr mServer;
     boost::shared_ptr<ChainedLogOut> mOut;
@@ -48,13 +48,59 @@ public:
 
 typedef IceUtil::Handle<FileItemI> FileItemIPtr;
 
+
+class FormatItemI : public FormatItem
+{
+public:
+    FormatItemI(const LoggingServerIPtr& server, const std::string& fmt)
+        : mServer(server)
+    {
+        printf("FormatItem constructor, this = %p\n",this);
+        formatSpec = fmt;
+        mServer->setFormat(fmt);
+    }
+    ~FormatItemI()
+    {
+    }
+private:
+    LoggingServerIPtr mServer;
+};
+
+typedef IceUtil::Handle<FormatItemI> FormatItemIPtr;
+
+class LevelItemI : public LevelItem
+{
+public:
+    LevelItemI(const LoggingServerIPtr& server, const std::string& name, const Level level)
+        : mServer(server), mName(name)
+    {
+        printf("LevelItem constructor, this = %p\n",this);
+        mServer->setLevel(name, level);
+    }
+    ~LevelItemI()
+    {
+    }
+private:
+    LoggingServerIPtr mServer;
+    std::string mName;
+};
+
+typedef IceUtil::Handle<LevelItemI> LevelItemIPtr;
+
+typedef std::map<std::string, LevelItemIPtr> LevelItemMap;
+
 class LoggerGeneralConfiguration : public IceUtil::Shared
 {
 public:
     LoggerGeneralConfiguration(const LoggerGeneralGroupPtr& group)
         : mGroup(group) { }
+
+    // Cache config items
     FileItemIPtr mOutputFile;
-    LoggerGeneralGroupPtr mGroup;
+    FormatItemIPtr mFormat;
+    LevelItemMap mLevels;
+
+    LoggerGeneralGroupPtr mGroup; // Note: This results in caching each item again as a generic item. 
 };
 
 typedef IceUtil::Handle<LoggerGeneralConfiguration> LoggerGeneralConfigurationPtr;
@@ -193,26 +239,26 @@ void LoggerConfigurationService::setConfiguration(const ConfigurationGroupSeq& g
             for (ConfigurationItemDict::const_iterator item = changedItems.begin();
                     item != changedItems.end();
                     ++item)
-   	        {
+   	    {
                 // If serial checking is to be skipped for this item just skip over it
                 if (item->second->serialNumber == -1)
-   	            {
-   	                continue;
-   	            }
+   	        {
+   	            continue;
+   	        }
 
-   	            ConfigurationItemDict::iterator localItem = localGroup->configurationItems.find(item->first);
+   	        ConfigurationItemDict::iterator localItem = localGroup->configurationItems.find(item->first);
 
-   	            if (localItem == localGroup->configurationItems.end())
-   	            {
-   	                // This is a new item so serial checking does not apply
-   		            continue;
-   	            }
+   	        if (localItem == localGroup->configurationItems.end())
+   	        {
+   	            // This is a new item so serial checking does not apply
+   	            continue;
+   	        }
 
-   	            if (item->second->serialNumber < localItem->second->serialNumber)
+   	        if (item->second->serialNumber < localItem->second->serialNumber)
                 {
                     throw SerialConflict(localGroup, localItem->second);
-   		        }
-   	        }
+                }
+   	    }
         }
 
         void visitLoggerGeneralGroup(const LoggerGeneralGroupPtr& group)
@@ -244,6 +290,17 @@ void LoggerConfigurationService::setConfiguration(const ConfigurationGroupSeq& g
 
                     mPriv->mGeneralConfiguration->mOutputFile = new FileItemI(mPriv->mServer, fileItem->fileName);
                 }
+                void visitFormatItem(const FormatItemPtr& formatItem)
+                {
+                    printf("Calling format constructor\n");
+                    mPriv->mGeneralConfiguration->mFormat = new FormatItemI(mPriv->mServer, formatItem->formatSpec);
+                    printf("Back from calling format constructor\n");
+                }
+                void visitLevelItem(const LevelItemPtr &levelItem)
+                {
+                    mPriv->mGeneralConfiguration->mLevels[levelItem->loggerName] = new LevelItemI(mPriv->mServer, levelItem->loggerName, levelItem->loggingLevel);
+                }
+
                 ConfigurationServicePrivPtr mPriv;
             };
 
@@ -253,8 +310,11 @@ void LoggerConfigurationService::setConfiguration(const ConfigurationGroupSeq& g
                     item != group->configurationItems.end();
                     ++item)
             {
-                mPriv->mGeneralConfiguration->mGroup->configurationItems.erase(item->first);
-                mPriv->mGeneralConfiguration->mGroup->configurationItems.insert(*item);
+                // Update our local copy of this item
+                mPriv->mGeneralConfiguration->mGroup->configurationItems.erase(item->first); 
+                mPriv->mGeneralConfiguration->mGroup->configurationItems.insert(*item);  
+
+                // Visit the item
                 item->second->visit(generalVisitor);
             }
         }
@@ -308,20 +368,38 @@ void LoggerConfigurationService::removeConfigurationItems(const ConfigurationGro
             class GeneralItemsVisitor : public LoggerConfigurationItemVisitor
             {
             public:
-                GeneralItemsVisitor(const LoggerGeneralConfigurationPtr& generalGroup)
-                    : mGroup(generalGroup) { }
+                GeneralItemsVisitor(const ConfigurationServicePrivPtr& priv)
+                    : mPriv(priv) { }
             private:
                 void visitFileItem(const FileItemPtr& fileItem)
                 {
-                    if (mGroup->mOutputFile && mGroup->mOutputFile->fileName == fileItem->fileName)
+                    if (mPriv->mGeneralConfiguration->mOutputFile && mPriv->mGeneralConfiguration->mOutputFile->fileName == fileItem->fileName)
+                    {
+                        FileItemIPtr fileItem = mPriv->mGeneralConfiguration->mOutputFile;
+                        mPriv->mGeneralConfiguration->mOutputFile = 0;
+                        mPriv->mServer->removeLogOut(fileItem->mOut);
+                    }
+                }
+                void visitFormatItem(const FormatItemPtr& formatItem)
+                {
+                    if (mPriv->mGeneralConfiguration->mFormat->formatSpec == formatItem->formatSpec)
                     {
-                        mGroup->mOutputFile = 0;
+                        mPriv->mGeneralConfiguration->mFormat->formatSpec = DefaultLogFormat;
+                        mPriv->mServer->setFormat(DefaultLogFormat);
                     }
                 }
-                LoggerGeneralConfigurationPtr mGroup;
+                void visitLevelItem(const LevelItemPtr &levelItem)
+                {
+                    if (mPriv->mGeneralConfiguration->mLevels.find(levelItem->loggerName) != mPriv->mGeneralConfiguration->mLevels.end())
+                    {
+                        mPriv->mGeneralConfiguration->mLevels.erase(levelItem->loggerName);
+                        mPriv->mServer->setLevel(levelItem->loggerName, DefaultLoggingLevel);
+                    }
+                }
+                ConfigurationServicePrivPtr mPriv;
             };
             
-            LoggerConfigurationItemVisitorPtr generalVisitor(new GeneralItemsVisitor(mPriv->mGeneralConfiguration));
+            LoggerConfigurationItemVisitorPtr generalVisitor(new GeneralItemsVisitor(mPriv));
 
             removeItems(generalVisitor, group->configurationItems, mPriv->mGeneralConfiguration->mGroup->configurationItems);
         }
diff --git a/server/src/LoggingServer.cpp b/server/src/LoggingServer.cpp
index 5433884..1391929 100644
--- a/server/src/LoggingServer.cpp
+++ b/server/src/LoggingServer.cpp
@@ -17,6 +17,7 @@
 #include <iomanip>
 
 #include <AsteriskSCF/Logger/Level.h>
+#include <AsteriskSCF/Logger/LogConsts.h>
 
 #include "LoggingServer.h"
 
@@ -29,7 +30,7 @@ const std::string RootLoggerProperty = LoggingServerI::LoggingPropertyPrefix
 const std::string LoggerPrefix = LoggingServerI::LoggingPropertyPrefix
     + "logger.";
 
-LoggingServerI::LoggingServerI()
+LoggingServerI::LoggingServerI() : mFormatter(DefaultLogFormat)
 {
     mSources[""] = SourceNode();
 }
@@ -76,23 +77,26 @@ void LoggingServerI::setLevel(const std::string& name, Level level)
     }
 }
 
-void LoggingServerI::logs(const std::string& name, Level level,
-    const std::string& message, const Ice::Current&) const
+void LoggingServerI::logs(const std::string& name, Level level, const std::string& message, 
+    const std::string& hostname, Ice::Long pid, 
+    const std::string& componentCategory, const std::string& serviceId, const std::string& componentId,
+    const Ice::Current&) const
 {
     if (isEnabledFor(name, level))
     {
+        std::string formattedMessage = mFormatter.formatMessage(message,name,level,hostname,pid,componentCategory, serviceId,componentId);
         if (!mLogsOut.empty())
         {
             for (std::vector<boost::shared_ptr<ChainedLogOut> >::const_iterator i = mLogsOut.begin();
                     i != mLogsOut.end(); ++ i)
             {
-                (*i)->logs(name, level, message);
+                (*i)->logs(name, level, formattedMessage);
             }
         }
         else
         {
             // we we don't have a LogOut, send to stderr.
-            ChainedLogOut::logs(std::clog, name, level, message);
+            ChainedLogOut::logs(std::clog, name, level, formattedMessage);
         }
     }
 }
@@ -186,3 +190,8 @@ void LoggingServerI::clearLogsOut()
 {
     mLogsOut.clear();
 }
+
+void LoggingServerI::setFormat(const std::string& fmtStr)
+{
+    mFormatter.setFormat(fmtStr);
+}
diff --git a/server/src/LoggingServer.h b/server/src/LoggingServer.h
index 1d5536b..3ad2b9d 100644
--- a/server/src/LoggingServer.h
+++ b/server/src/LoggingServer.h
@@ -23,6 +23,8 @@
 #include <Ice/Properties.h>
 
 #include <AsteriskSCF/System/Logger/LoggerIf.h>
+#include <AsteriskSCF/Logger/LogFormatter.h>
+#include <AsteriskSCF/Logger/LogConsts.h>
 #include "ChainedLogOut.h"
 
 namespace AsteriskSCF
@@ -36,7 +38,7 @@ class SourceNode
 {
 public:
     SourceNode() :
-        mLogLevel(Debug)
+        mLogLevel(DefaultLoggingLevel)
     {
     }
 
@@ -64,8 +66,11 @@ class LoggingServerI : public LoggingServer
 public:
     ASTSCF_DLL_EXPORT LoggingServerI();
 
-    ASTSCF_DLL_EXPORT void logs(const std::string&, Level,
-        const std::string&, const Ice::Current&) const;
+    ASTSCF_DLL_EXPORT void logs(const std::string& name, Level, const std::string& msg, 
+        const std::string& hostname, Ice::Long pid, 
+        const std::string& componentCategory, const std::string& serviceId, const std::string& componentId,
+        const Ice::Current&) const;
+
     Configuration getConfiguration(const Ice::Current&) const
     {
         return getConfiguration();
@@ -82,10 +87,12 @@ public:
     void addLogOut(const boost::shared_ptr<ChainedLogOut> &out);
     void clearLogsOut();
 
+    void setFormat(const std::string& fmtStr);
+
     static const std::string LoggingPropertyPrefix;
 
 private:
-    /** Keep sources in a revers-sorted map. */
+    /** Keep sources in a reverse-sorted map. */
     typedef std::map<std::string, SourceNode, std::greater<std::string> >
     Sources;
 
@@ -100,6 +107,7 @@ private:
 
     IceUtil::Mutex mSourcesMutex;
     Sources mSources;
+    LogFormatter mFormatter;
 
     ServerConfigurationListenerPrx mConfigurationListener;
 
diff --git a/server/test/CMakeLists.txt b/server/test/CMakeLists.txt
index 9273009..ee98fd3 100644
--- a/server/test/CMakeLists.txt
+++ b/server/test/CMakeLists.txt
@@ -14,8 +14,8 @@ astscf_component_add_files(LoggingConfigurationTest ConfigurationTest.cpp)
 astscf_component_add_files(LoggingConfigurationTest LoggingConfigurationHelper.cpp)
 astscf_component_add_files(LoggingConfigurationTest LoggingConfigurationHelper.h)
 astscf_component_add_slices(LoggingConfigurationTest PROJECT AsteriskSCF/Configuration/LoggingService/LoggingConfigurationIf.ice)
-astscf_component_add_boost_libraries(LoggingConfigurationTest unit_test_framework)
+astscf_component_add_boost_libraries(LoggingConfigurationTest unit_test_framework system)
 astscf_component_add_slice_collection_libraries(LoggingConfigurationTest ASTSCF)
 astscf_component_build_icebox(LoggingConfigurationTest)
-target_link_libraries(LoggingConfigurationTest)
+target_link_libraries(LoggingConfigurationTest astscf-api logging-service-lib logging-client)
 astscf_test_icebox(LoggingConfigurationTest server/config/testloggingserver.conf)
diff --git a/server/test/ConfigurationTest.cpp b/server/test/ConfigurationTest.cpp
index 5209ebc..7f1b983 100644
--- a/server/test/ConfigurationTest.cpp
+++ b/server/test/ConfigurationTest.cpp
@@ -21,16 +21,27 @@
 #include <boost/test/debug.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/asio/ip/host_name.hpp>
+#include <boost/interprocess/detail/os_thread_functions.hpp>
 
 #include <Ice/Ice.h>
 #include <IceBox/IceBox.h>
 
 #include <AsteriskSCF/System/Component/ConfigurationIf.h>
+#include <AsteriskSCF/Logger/IceLogger.h>
+#include <AsteriskSCF/logger.h>
 
 #include "LoggingConfigurationHelper.h"
 
 using namespace AsteriskSCF::System::Configuration::V1;
 using namespace AsteriskSCF::Configuration::LoggingService::V1;
+using namespace AsteriskSCF::System::Logging;
+
+namespace
+{
+    std::string LoggerName("AsteriskSCF.TestLogger");
+    Logger lg = getLoggerFactory().getLogger(LoggerName);
+}
 
 /* Cache the command line arguments so that Ice can be initialized within the global fixture. */
 struct ArgCacheType
@@ -96,8 +107,13 @@ struct GlobalIceFixture
 
             TestBed.communicator = Ice::initialize(initData);
             TestBed.adapter = TestBed.communicator->createObjectAdapterWithEndpoints("LoggerTestAdapter", "default");
+            ConfiguredIceLoggerPtr mIceLogger = createIceLogger(TestBed.adapter);
+            mIceLogger->getLogger().setComponentInfo("TestComponentCategory", "default", "TestInstance");
+            getLoggerFactory().setLogOutput(mIceLogger->getLogger());
+            TestBed.adapter->activate();
+
             Ice::PropertiesPtr communicatorProps = TestBed.communicator->getProperties();
-            std::string proxyProp = communicatorProps->getProperty("Logger.Proxy");
+            std::string proxyProp = communicatorProps->getProperty("LoggerConfiguration.Proxy");
             Ice::ObjectPrx loggerObj = TestBed.communicator->stringToProxy(proxyProp);
             ConfigurationServicePrx confPrx = ConfigurationServicePrx::checkedCast(loggerObj);
             TestBed.confHelper.reset(new LoggingConfigurationHelper(confPrx));
@@ -226,6 +242,84 @@ BOOST_AUTO_TEST_CASE(PurposefulSerialConflict)
     BOOST_CHECK(exceptionHit == true);
     status = checkConfiguredFile(TestBed.confHelper, fileName1);
     BOOST_CHECK(status == CORRECT);
+    TestBed.confHelper->removeLogOutFile(fileName1);
+    status = checkConfiguredFile(TestBed.confHelper, fileName1);
+    BOOST_CHECK(status == NONEXISTENT);
+}
+
+BOOST_AUTO_TEST_CASE(SetLevel)
+{
+    try
+    {
+        TestBed.confHelper->setLoggingLevel(LoggerName, Info, serial++);
+        TestBed.confHelper->setLoggingLevel("", Error, serial++);
+    }
+    catch (const std::exception& e)
+    {
+        std::string s("Exception configuring logging level: ");
+        s = s + e.what();
+        BOOST_FAIL(s);
+    }
+
+    try
+    {
+        Level level = TestBed.confHelper->getLoggingLevel(LoggerName);
+        BOOST_CHECK(Info == level);
+
+        level = TestBed.confHelper->getLoggingLevel("");
+        BOOST_CHECK(Error == level);
+    }
+    catch (const std::exception& e)
+    {
+        std::string s("Exception retrieving logging level: ");
+        s = s + e.what();
+        BOOST_FAIL(s);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(SetFormat)
+{
+
+    BOOST_TEST_MESSAGE("TEST");
+    printf("--------------------------------------------------\n");
+    const std::string fileName("./Testing/Temporary/logformat.txt");
+    const std::string fileName2("./Testing/Temporary/logformat2.txt");
+    try
+    {
+        TestBed.confHelper->setLogOutFile(fileName, serial++);
... 365 lines suppressed ...


-- 
asterisk-scf/release/logger.git



More information about the asterisk-scf-commits mailing list