aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-04-20 00:28:38 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-04-20 00:28:38 +0000
commit41e24050e2715fca651518ba37db0ef0e5399534 (patch)
treefa4720fab50ec3551f2f7265242776f768e72679
parenta33faa0bab635ad9454260b769fe70f56196cf95 (diff)
downloadpaludis-41e24050e2715fca651518ba37db0ef0e5399534.tar.gz
paludis-41e24050e2715fca651518ba37db0ef0e5399534.tar.xz
More flexible logger class
-rw-r--r--paludis/util/log.cc40
-rw-r--r--paludis/util/log.hh56
-rw-r--r--paludis/util/log_TEST.cc71
3 files changed, 156 insertions, 11 deletions
diff --git a/paludis/util/log.cc b/paludis/util/log.cc
index e7debb7..1b59d0b 100644
--- a/paludis/util/log.cc
+++ b/paludis/util/log.cc
@@ -18,6 +18,7 @@
*/
#include <iostream>
+#include <exception>
#include <paludis/util/log.hh>
/** \file
@@ -74,7 +75,7 @@ Log::log_level() const
}
void
-Log::message(const LogLevel l, const LogContext c, const std::string & s)
+Log::_message(const LogLevel l, const LogContext c, const std::string & s)
{
if (l >= _imp->log_level)
{
@@ -121,6 +122,25 @@ Log::message(const LogLevel l, const LogContext c, const std::string & s)
}
}
+LogMessageHandler::LogMessageHandler(const LogMessageHandler & o) :
+ _message(o._message),
+ _log_level(o._log_level),
+ _log_context(o._log_context)
+{
+}
+
+void
+Log::message(const LogLevel l, const LogContext c, const std::string & s)
+{
+ _message(l, c, s);
+}
+
+LogMessageHandler
+Log::message(const LogLevel l, const LogContext c)
+{
+ return LogMessageHandler(l, c);
+}
+
void
Log::set_log_stream(std::ostream * const s)
{
@@ -161,3 +181,21 @@ Log::set_program_name(const std::string & s)
_imp->program_name = s;
}
+LogMessageHandler::LogMessageHandler(const LogLevel l, const LogContext c) :
+ _log_level(l),
+ _log_context(c)
+{
+}
+
+void
+LogMessageHandler::_append(const std::string & s)
+{
+ _message.append(s);
+}
+
+LogMessageHandler::~LogMessageHandler()
+{
+ if (! std::uncaught_exception() && ! _message.empty())
+ Log::get_instance()->_message(_log_level, _log_context, _message);
+}
+
diff --git a/paludis/util/log.hh b/paludis/util/log.hh
index 6584e57..6fdd60d 100644
--- a/paludis/util/log.hh
+++ b/paludis/util/log.hh
@@ -66,6 +66,8 @@ namespace paludis
last_lc
};
+ class LogMessageHandler;
+
/**
* Singleton class that handles log messages.
*
@@ -76,10 +78,13 @@ namespace paludis
private PrivateImplementationPattern<Log>
{
friend class InstantiationPolicy<Log, instantiation_method::SingletonTag>;
+ friend class LogMessageHandler;
private:
Log();
+ void _message(const LogLevel, const LogContext, const std::string &);
+
public:
/**
* Destructor, to be called only by our InstantiationPolicy.
@@ -103,6 +108,16 @@ namespace paludis
void message(const LogLevel, const LogContext, const std::string &);
/**
+ * Log a message.
+ *
+ * The return value can be appended to using
+ * LogMessageHandler::operator<<(). When the return value is
+ * destroyed (that is to say, at the end of the statement), the log
+ * message is written.
+ */
+ LogMessageHandler message(const LogLevel, const LogContext) PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ /**
* Change the log stream.
*/
void set_log_stream(std::ostream * const);
@@ -114,6 +129,47 @@ namespace paludis
};
/**
+ * Used by Log::message().
+ *
+ * \see Log
+ * \ingroup grplog
+ */
+ class PALUDIS_VISIBLE LogMessageHandler
+ {
+ friend LogMessageHandler Log::message(const LogLevel, const LogContext);
+
+ private:
+ std::string _message;
+ LogLevel _log_level;
+ LogContext _log_context;
+
+ LogMessageHandler(const LogMessageHandler &);
+ LogMessageHandler(const LogLevel, const LogContext);
+ void operator= (const LogMessageHandler &);
+
+ void _append(const std::string & s);
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ ~LogMessageHandler();
+
+ ///\}
+
+ /**
+ * Append some text to our message.
+ */
+ template <typename T_>
+ LogMessageHandler &
+ operator<< (const T_ & t)
+ {
+ _append(stringify(t));
+ return *this;
+ }
+ };
+
+ /**
* Stringify a LogLevel constant.
*
* \ingroup grplog
diff --git a/paludis/util/log_TEST.cc b/paludis/util/log_TEST.cc
index 608fa37..792d8f0 100644
--- a/paludis/util/log_TEST.cc
+++ b/paludis/util/log_TEST.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -31,19 +31,43 @@
using namespace paludis;
using namespace test;
+namespace
+{
+ struct Monkey
+ {
+ };
+
+ std::ostream &
+ operator<< (std::ostream &, const Monkey &) PALUDIS_ATTRIBUTE((noreturn));
+
+ std::ostream &
+ operator<< (std::ostream &, const Monkey & m)
+ {
+ throw m;
+ }
+
+ int throws_a_monkey() PALUDIS_ATTRIBUTE((noreturn));
+ int throws_a_monkey()
+ {
+ throw Monkey();
+ }
+
+ Monkey throws_a_monkey_when_stringified()
+ {
+ return Monkey();
+ }
+}
+
namespace test_cases
{
- /**
- * \test Test Log.
- *
- * \ingroup grptestcases
- */
struct LogTest : TestCase
{
LogTest() : TestCase("log") { }
void run()
{
+ Log::destroy_instance();
+
TEST_CHECK(Log::get_instance());
TEST_CHECK(Log::get_instance() == Log::get_instance());
@@ -52,7 +76,7 @@ namespace test_cases
Log::get_instance()->set_log_level(ll_debug);
TEST_CHECK(s.str().empty());
- Log::get_instance()->message(ll_debug, lc_no_context, "one");
+ Log::get_instance()->message(ll_debug, lc_no_context) << "one";
TEST_CHECK(! s.str().empty());
TEST_CHECK(std::string::npos != s.str().find("one"));
@@ -61,14 +85,41 @@ namespace test_cases
TEST_CHECK(t.str().empty());
Log::get_instance()->set_log_level(ll_warning);
- Log::get_instance()->message(ll_debug, lc_no_context, "two");
+ Log::get_instance()->message(ll_debug, lc_no_context) << "two";
TEST_CHECK(t.str().empty());
- Log::get_instance()->message(ll_warning, lc_no_context, "three");
+ Log::get_instance()->message(ll_warning, lc_no_context) << "three" << "." << 14;
TEST_CHECK(! t.str().empty());
TEST_CHECK(std::string::npos == t.str().find("one"));
TEST_CHECK(std::string::npos == t.str().find("two"));
- TEST_CHECK(std::string::npos != t.str().find("three"));
+ TEST_CHECK(std::string::npos != t.str().find("three.14"));
}
} test_log;
+
+ struct LogExceptionTest : TestCase
+ {
+ LogExceptionTest() : TestCase("log exception") { }
+
+ void run()
+ {
+ Log::destroy_instance();
+
+ std::stringstream s;
+ Log::get_instance()->set_log_stream(&s);
+ Log::get_instance()->set_log_level(ll_debug);
+ TEST_CHECK(s.str().empty());
+
+ TEST_CHECK_THROWS(Log::get_instance()->message(ll_debug, lc_no_context) << throws_a_monkey(), Monkey);
+ TEST_CHECK(s.str().empty());
+ TEST_CHECK_THROWS(Log::get_instance()->message(ll_debug, lc_no_context)
+ << "one" << throws_a_monkey() << "two", Monkey);
+ TEST_CHECK(s.str().empty());
+
+ TEST_CHECK_THROWS(Log::get_instance()->message(ll_debug, lc_no_context) << throws_a_monkey_when_stringified(), Monkey);
+ TEST_CHECK(s.str().empty());
+ TEST_CHECK_THROWS(Log::get_instance()->message(ll_debug, lc_no_context)
+ << "one" << throws_a_monkey_when_stringified() << "two", Monkey);
+ TEST_CHECK(s.str().empty());
+ }
+ } test_log_exception;
}