[asterisk-scf-commits] asterisk-scf/integration/logger.git branch "logformat2" created.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Fri Sep 2 17:51:48 CDT 2011
branch "logformat2" has been created
at fb443735377d9e1488c469c09f98501008cddd78 (commit)
- Log -----------------------------------------------------------------
commit fb443735377d9e1488c469c09f98501008cddd78
Author: Ken Hunt <ken.hunt at digium.com>
Date: Fri Sep 2 17:45:58 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..6d7fa60
--- /dev/null
+++ b/client/src/LogFormatter.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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 <AsteriskSCF/logger.h>
+
+using namespace AsteriskSCF::System::Logging;
+using namespace std;
+
+LogFormatter::LogFormatter(const std::string& fmtStr) :
+ mFormat(fmtStr)
+{
+}
+
+LogFormatter::~LogFormatter()
+{
+}
+
+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(SPECIFIER("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(SPECIFIER("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(SPECIFIER("n"),0)) != std::string::npos)
+ {
+ // Logger name
+ outStr.replace(pos,2,name);
+ }
+
+ if ((pos=outStr.find(SPECIFIER("l"),0)) != std::string::npos)
+ {
+ // Priority / level
+ std::stringstream s("");
+
+ s << level;
+ outStr.replace(pos,2,s.str());
+ }
+
+ if ((pos=outStr.find(SPECIFIER("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(SPECIFIER("p"),0)) != std::string::npos)
+ {
+ // Process ID
+ outStr.replace(pos,2,boost::lexical_cast<std::string>(pid));
+ }
+
+ if ((pos=outStr.find(SPECIFIER("C"),0)) != std::string::npos)
+ {
+ outStr.replace(pos, 2, componentCategory);
+ }
+
+ if ((pos=outStr.find(SPECIFIER("S"),0)) != std::string::npos)
+ {
+ outStr.replace(pos, 2, serviceId);
+ }
+
+ if ((pos=outStr.find(SPECIFIER("I"),0)) != std::string::npos)
+ {
+ outStr.replace(pos, 2, instanceId);
+ }
+
+ if ((pos=outStr.find(SPECIFIER("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..45e1fb7 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>
@@ -22,6 +23,7 @@
#include <iostream>
+#include <boost/filesystem.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/thread/once.hpp>
#include <AsteriskSCF/logger.h>
@@ -35,6 +37,7 @@ namespace
boost::once_flag oneFactory = BOOST_ONCE_INIT;
LoggerFactory *loggerFactory = 0;
+
void initLoggerFactory()
{
static boost::shared_ptr<LogOut> out = buildOstreamLogger(std::cout);
@@ -44,6 +47,46 @@ void initLoggerFactory()
}
+
+/**
+ * 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(SPECIFIER("l"),0))!=std::string::npos)
+ {
+ s.replace(pos,2,boost::lexical_cast<std::string>(line));
+ found = true;
+ }
+ if ((pos=s.find(SPECIFIER("f"),0))!=std::string::npos)
+ {
+ s.replace(pos,2,boost::lexical_cast<std::string>(fcn));
+ found = true;
+ }
+ if ((pos=s.find(SPECIFIER("sp"),0))!=std::string::npos)
+ {
+ s.replace(pos,3,boost::lexical_cast<std::string>(file));
+ found = true;
+ }
+ if ((pos=s.find(SPECIFIER("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;
+}
+
+
LoggerFactory& AsteriskSCF::System::Logging::getLoggerFactory()
{
boost::call_once(initLoggerFactory, oneFactory);
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..65c0693
--- /dev/null
+++ b/include/AsteriskSCF/Logger/LogFormatter.h
@@ -0,0 +1,113 @@
+/*
+ * 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>
+
+/**
+ * Prepends a format specifier identifier onto a format specifier string for the logger format string.
+ * This is a macro to make it easy to change this character, like to a % or something else if desired.
+ */
+#define SPECIFIER(S) "$" S
+
+/**
+ * Macro for getting some source information into a log message.
+ * @param S formatting string for macro, can have the following specifiers (note: the $ is really whatever the SPECIFIER macro uses) :
+ * $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..0db02e8 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)
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++);
+ TestBed.confHelper->setLogOutFile(fileName2, serial++);
+ TestBed.confHelper->setLoggingLevel(LoggerName, Debug, serial++);
+ }
+ catch (const SerialConflict&)
+ {
+ BOOST_FAIL("SerialConflict thrown when setting output file");
+ }
+ // Use default format of "logger_name:msg_level:msg"
+ lg(Info) << "Informational message";
+ // Set format to "timestamp: message: logger_name,msg_level"
+ TestBed.confHelper->setFormat(std::string("$t: $m: $n,$l"),serial++);
... 1559 lines suppressed ...
--
asterisk-scf/integration/logger.git
More information about the asterisk-scf-commits
mailing list