// Boost general library logging.hpp header file ---------------------------//
// (C) Copyright Jean-Daniel Michaud 2007. Permission to copy, use, modify,
// sell and distribute this software is granted provided this copyright notice
// appears in all copies. This software is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
// See http://www.boost.org/LICENSE_1_0.txt for licensing.
// See http://code.google.com/p/loglite/ for library home page.
#ifndef BOOST_LOGGING_HPP
#define BOOST_LOGGING_HPP
#include <list>
#include <stack>
#include <string>
#include <ostream>
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <exception>
#include <boost/shared_ptr.hpp>
#include <boost/tuple/tuple.hpp>
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_THREADS)
# include <boost/thread/thread.hpp>
# include <boost/thread/condition.hpp>
#endif // BOOST_HAS_THREADS
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/format.hpp>
#ifndef BOOST_NO_CODE_GENERATION_FOR_LOG
#define BOOST_LOG_INIT( format ) \
{ \
boost::logging::logger *l = boost::logging::logger::get_instance(); \
assert(l); \
l->add_format(format); \
}
#define BOOST_LOG_ADD_OUTPUT_STREAM( sink ) \
{ \
boost::logging::logger *l = boost::logging::logger::get_instance(); \
assert(l); \
l->add_sink(sink); \
}
#define BOOST_LOG(level, qualifier, _trace) \
{ \
boost::logging::logger *l = boost::logging::logger::get_instance(); \
assert(l); \
if (l->get_global_max_log_level() >= level) \
{ \
if (l->m_string_stream.str() != "") \
l->m_string_stack.push(l->m_string_stream.str()); \
\
l->m_string_stream.str(""); \
l->m_string_stream << _trace; \
l->trace(level, qualifier, l->m_string_stream.str(), __FILE__, __LINE__); \
if (!l->m_string_stack.empty()) \
{ \
l->m_string_stream.str(l->m_string_stack.top()); \
l->m_string_stack.pop(); \
} \
} \
}
#define BOOST_LOG_( level, _trace ) \
{ BOOST_LOG(level, boost::logging::log, _trace) }
#define BOOST_LOG_UNFORMATTED(level, qualifier, _trace) \
{ \
boost::logging::logger *l = boost::logging::logger::get_instance(); \
assert(l); \
if (l->get_global_max_log_level() >= level) \
{ \
if (l->m_string_stream.str() != "") \
l->m_string_stack.push(l->m_string_stream.str()); \
\
l->m_string_stream.str(""); \
l->m_string_stream << _trace; \
l->unformatted_trace(level, qualifier, \
l->m_string_stream.str(), __FILE__, __LINE__); \
if (!l->m_string_stack.empty()) \
{ \
l->m_string_stream.str(l->m_string_stack.top()); \
l->m_string_stack.pop(); \
} \
} \
}
#define BOOST_LOG_FINALIZE() \
{ \
boost::logging::logger *l = boost::logging::logger::get_instance(); \
assert(l); \
l->clear(); \
}
#else // !BOOST_NO_CODE_GENERATION_FOR_LOG
#define BOOST_LOG_INIT( format )
#define BOOST_LOG_ADD_OUTPUT_STREAM( sink )
#define BOOST_LOG(level, qualifier, _trace)
#define BOOST_LOG_( level, _trace )
#define BOOST_LOG_UNFORMATTED(level, qualifier, _trace)
#endif // BOOST_NO_CODE_GENERATION_FOR_LOG
#define BOOST_MAX_LINE_STR_SIZE 20 // log(2^64)
#define BOOST_LEVEL_UP_LIMIT 999
namespace boost {
namespace logging {
// Logging forward declarations ---------------------------------------------//
class log_element;
class level_element;
class qualifier;
class trace_element;
class format;
class sink;
class logger;
// Logging typedefs declarations --------------------------------------------//
typedef enum { LEVEL = 0, QUALIFIER, TRACE, FILENAME, LINE } param_e;
typedef enum { SINK = 0, FORMAT } sink_format_assoc_e;
typedef std::list<boost::shared_ptr<log_element> > element_list_t;
typedef std::list<boost::shared_ptr<std::ostream> > stream_list_t;
typedef unsigned short level_t;
typedef tuple<level_t,
const qualifier *,
std::string,
std::string,
unsigned int> log_param_t;
typedef std::list<format> format_list_t;
typedef tuple<sink, format&> sink_format_assoc_t;
typedef std::list<sink_format_assoc_t> sink_format_assoc_list_t;
typedef std::list<qualifier *> qualifier_list_t;
// Used for shared_ptr() on statically allocated log_element ----------------//
struct null_deleter
{ void operator()(void const *) const {} };
// Qualifier class declaration ----------------------------------------------//
class qualifier
{
public:
qualifier() {}
inline std::string to_string() const { return m_identifier; }
virtual bool operator==(const qualifier &q) { return false; }
protected:
std::string m_identifier;
};
class log_qualifier : public qualifier
{
public:
log_qualifier() { m_identifier = "log"; }
bool operator==(const qualifier &q)
{ return (dynamic_cast<const log_qualifier *>(&q) != NULL); }
};
class notice_qualifier : public qualifier
{
public:
notice_qualifier() { m_identifier = "notice"; }
bool operator==(const qualifier &q)
{ return (dynamic_cast<const notice_qualifier *>(&q) != NULL); }
};
class warning_qualifier : public qualifier
{
public:
warning_qualifier() { m_identifier = "warning"; }
bool operator==(const qualifier &q)
{ return (dynamic_cast<const warning_qualifier *>(&q) != NULL); }
};
class error_qualifier : public qualifier
{
public:
error_qualifier() { m_identifier = "error"; }
bool operator==(const qualifier &q)
{ return (dynamic_cast<const error_qualifier *>(&q) != NULL); }
};
// Element classes declaration ---------------------------------------------//
class log_element
{
public:
virtual std::string to_string() { assert(0); return ""; };
virtual std::string visit(format &f, const log_param_t &log_param);
};
class level_element : public log_element
{
public:
std::string to_string(level_t l)
{
return str(boost::format("%i") % l);
};
std::string visit(format &f, const log_param_t &log_param);
};
class filename_element : public log_element
{
public:
std::string to_string(const std::string &f) { return f; }
std::string visit(format &f, const log_param_t &log_param);
};
class line_element : public log_element
{
public:
std::string to_string(unsigned int l)
{
return str(boost::format("%i") % l);
}
std::string visit(format &f, const log_param_t &log_param);
};
class date_element : public log_element
{
public:
std::string to_string()
{
boost::gregorian::date d(boost::gregorian::day_clock::local_day());
return boost::gregorian::to_iso_extended_string(d);
}
};
class time_element : public log_element
{
public:
std::string to_string()
{
boost::posix_time::ptime
t(boost::posix_time::microsec_clock::local_time());
return boost::posix_time::to_simple_string(t);
};
};
class trace_element : public log_element
{
public:
std::string to_string(const std::string& s) { return s; };
std::string visit(format &f, const log_param_t &log_param);
};
class eol_element : public log_element
{
public:
std::string to_string() { return "\n"; };
};
class literal_element : public log_element
{
public:
explicit literal_element(const std::string &l) : m_literal(l) {}
std::string to_string() { return m_literal; };
private:
std::string m_literal;
};
class qualifier_element : public log_element
{
public:
qualifier_element(const qualifier &lq)
{
m_qualifier_identifier = lq.to_string();
}
std::string to_string() { return m_qualifier_identifier; };
private:
std::string m_qualifier_identifier;
};
// Format class declatation -------------------------------------------------//
class format
{
public:
format(log_element &e)
: m_identifier("unnamed")
{
boost::shared_ptr<boost::logging::log_element> p(&e, null_deleter());
m_element_list.push_back(p);
}
format(log_element &e, const std::string &identifier)
: m_identifier(identifier)
{
boost::shared_ptr<boost::logging::log_element> p(&e, null_deleter());
m_element_list.push_back(p);
}
format(element_list_t e)
: m_element_list(e), m_identifier("unnamed") {}
format(element_list_t e, const std::string &identifier)
: m_element_list(e), m_identifier(identifier) {}
std::string produce_trace(const log_param_t &log_param)
{
element_list_t::iterator e_it = m_element_list.begin();
std::stringstream str_stream;
for (; e_it != m_element_list.end(); ++e_it)
{
str_stream << (*e_it)->visit(*this, log_param);
}
return str_stream.str();
}
// Visitors for the log elements
std::string accept(log_element &e)
{
return e.to_string();
}
std::string accept(level_element &e, level_t l)
{
return e.to_string(l);
}
std::string accept(trace_element &e, const std::string& s)
{
return e.to_string(s);
}
std::string accept(filename_element &e, const std::string& s)
{
return e.to_string(s);
}
std::string accept(line_element &e, unsigned int l)
{
return e.to_string(l);
}
private:
element_list_t m_element_list;
std::string m_identifier;
};
// Sink class declaration ---------------------------------------------------//
class sink
{
public:
sink(std::ostream *s, level_t max_log_level = 1)
{
if (s)
if (*s == std::cout || *s == std::cerr || *s == std::clog)
m_output_stream.reset(s, null_deleter());
else
m_output_stream.reset(s);
set_max_log_level(max_log_level);
}
void set_max_log_level(level_t max_log_level)
{
m_max_log_level = ((BOOST_LEVEL_UP_LIMIT < max_log_level)
? BOOST_LEVEL_UP_LIMIT : max_log_level);
}
inline level_t get_max_log_level() const { return m_max_log_level; }
void consume_trace(format &f, const log_param_t &log_param)
{
/* make here check to avoid producing a useless trace */
if (get<LEVEL>(log_param) > m_max_log_level)
return ;
qualifier_list_t::const_iterator it = m_qualifier_list.begin();
bool qualifier_present = false;
for ( ; !qualifier_present && it != m_qualifier_list.end(); ++it)
qualifier_present = (**it == *get<QUALIFIER>(log_param));
if (!qualifier_present)
return ;
*m_output_stream << f.produce_trace(log_param);
}
void attach_qualifier(qualifier &q)
{
m_qualifier_list.push_back(&q);
}
private:
level_t m_max_log_level;
shared_ptr<std::ostream> m_output_stream;
qualifier_list_t m_qualifier_list;
};
// Element static instantiations --------------------------------------------//
static level_element level = level_element();
static filename_element filename = filename_element();
static line_element line = line_element();
static date_element date = date_element();
static time_element time = time_element();
static trace_element trace = trace_element();
static eol_element eol = eol_element();
static log_qualifier log = log_qualifier();
static notice_qualifier notice = notice_qualifier();
static warning_qualifier warning = warning_qualifier();
static error_qualifier error = error_qualifier();
// Logger class declaration ------------------------------------------------//
class logger
{
public:
logger() : m_global_max_log_level(0) {}
void clear()
{
m_format_list.clear();
m_sink_format_assoc.clear();
}
static logger *get_instance()
{
#if defined(BOOST_HAS_THREADS)
static boost::mutex m_inst_mutex;
boost::mutex::scoped_lock scoped_lock(m_inst_mutex);
#endif // BOOST_HAS_THREADS
static logger *l = NULL;
if (!l)
{
l = new logger();
static shared_ptr<logger> s_ptr_l(l);
}
return l;
}
void add_format(const format &f)
{
m_format_list.push_back(f);
}
void add_sink(const sink &s)
{
if (m_format_list.begin() == m_format_list.end())
throw "no format defined";
// Updating global_max_level used for full lazy evaluation
m_global_max_log_level =
(m_global_max_log_level < s.get_max_log_level())
?
s.get_max_log_level()
:
m_global_max_log_level;
m_sink_format_assoc.push_back
(
sink_format_assoc_t(s, *m_format_list.begin())
);
}
void add_sink(const sink &s, format &f)
{
// Updating global_max_level used for full lazy evaluation
m_global_max_log_level =
(m_global_max_log_level < s.get_max_log_level())
?
s.get_max_log_level()
:
m_global_max_log_level;
m_sink_format_assoc.push_back(sink_format_assoc_t(s, f));
}
inline level_t get_global_max_log_level()
{ return m_global_max_log_level; }
void trace(unsigned short l,
const qualifier &q,
const std::string &t,
const std::string &f,
unsigned int ln)
{
#if defined(BOOST_HAS_THREADS)
boost::mutex::scoped_lock scoped_lock(m_mutex);
#endif // BOOST_HAS_THREADS
log_param_t log_param(l, &q, t, f, ln);
sink_format_assoc_list_t::iterator
s_it = m_sink_format_assoc.begin();
for (; s_it != m_sink_format_assoc.end(); ++s_it)
{
get<SINK>(*s_it).consume_trace(get<FORMAT>(*s_it), log_param);
}
}
void unformatted_trace(unsigned short l,
const qualifier &q,
const std::string &t,
const std::string &f,
unsigned int ln);
public:
std::stringstream m_string_stream;
std::stack<std::string> m_string_stack;
private:
format_list_t m_format_list;
sink_format_assoc_list_t m_sink_format_assoc;
// The global max log level is the highest log level on all the link
// added to the logger. If no sink as a log level high enougth for
// a trace, the trace does not need to be evaluated.
level_t m_global_max_log_level;
#if defined(BOOST_HAS_THREADS)
boost::mutex m_mutex;
#endif // BOOST_HAS_THREADS
}; // logger
// Element functions definition ---------------------------------------------//
inline std::string log_element::visit(format &f,
const log_param_t &log_param)
{
return f.accept(*this);
}
inline std::string level_element::visit(format &f,
const log_param_t &log_param)
{
return f.accept(*this, get<LEVEL>(log_param));
}
inline std::string trace_element::visit(format &f,
const log_param_t &log_param)
{
return f.accept(*this, get<TRACE>(log_param));
}
inline std::string filename_element::visit(format &f,
const log_param_t &log_param)
{
return f.accept(*this, get<FILENAME>(log_param));
}
inline std::string line_element::visit(format &f,
const log_param_t &log_param)
{
return f.accept(*this, get<LINE>(log_param));
}
} // !namespace logging
} // !namespace boost
// Element global operators -------------------------------------------------//
inline boost::logging::element_list_t operator>>(
boost::logging::log_element &lhs,
boost::logging::log_element &rhs)
{
boost::logging::element_list_t l;
l.push_back(boost::shared_ptr<boost::logging::log_element>
(&lhs, boost::logging::null_deleter()));
l.push_back(boost::shared_ptr<boost::logging::log_element>
(&rhs, boost::logging::null_deleter()));
return l;
}
inline boost::logging::element_list_t operator>>(
boost::logging::element_list_t lhs,
boost::logging::log_element &rhs)
{
lhs.push_back(boost::shared_ptr<boost::logging::log_element>
(&rhs, boost::logging::null_deleter()));
return lhs;
}
inline boost::logging::element_list_t operator>>(
const std::string &s,
boost::logging::log_element &rhs)
{
boost::logging::element_list_t l;
boost::shared_ptr<boost::logging::literal_element>
p(new boost::logging::literal_element(s));
l.push_back(p);
l.push_back(boost::shared_ptr<boost::logging::log_element>
(&rhs, boost::logging::null_deleter()));
return l;
}
inline boost::logging::element_list_t operator>>(
boost::logging::element_list_t lhs,
const std::string &s)
{
boost::shared_ptr<boost::logging::literal_element>
p(new boost::logging::literal_element(s));
lhs.push_back(p);
return lhs;
}
inline
void boost::logging::logger::unformatted_trace(unsigned short l,
const qualifier &q,
const std::string &t,
const std::string &f,
unsigned int ln)
{
#if defined(BOOST_HAS_THREADS)
boost::mutex::scoped_lock scoped_lock(m_mutex);
#endif // BOOST_HAS_THREADS
log_param_t log_param(l, &q, t, f, ln);
sink_format_assoc_list_t::iterator
s_it = m_sink_format_assoc.begin();
for (; s_it != m_sink_format_assoc.end(); ++s_it)
{
boost::logging::format f(boost::logging::trace);
get<SINK>(*s_it).consume_trace(f, log_param);
}
}
#endif // !BOOST_LOGGING_HPP