#ifndef __CAE_TUPLE_LOG_H #define __CAE_TUPLE_LOG_H #include #include #include #include #include "log.h" namespace tuple_log { // The proposed BOOST_ENUM might be a nice replacement for this class: struct level { enum value_type { trace, debug, info, warning, error, fatal, default_value = info } value; level () : value (default_value) {} level (value_type l) : value (l) {} /// Get the name of this level const char* name () const { return name (value); } /// Convert a level to a string representation static const char* name (value_type val) { const char* str = ""; switch (val) { case trace : str = "trace"; break; case debug : str = "debug"; break; case info : str = "info"; break; case warning : str = "warning"; break; case error : str = "error"; break; case fatal : str = "fatal"; break; default : break; } return str; } }; // Stream formatting for a level object std::ostream& operator<< (std::ostream& os, const level& l) { return os << l.name (); } // The proposed BOOST_ENUM might be a nice replacement for this class: struct category { enum value_type { program_flow = 0x01, function_arguments = 0x02, return_value = 0x04, data_flow = 0x08, default_value = program_flow, all_categories = 0xffff } value; category () : value (default_value) {} category (value_type t) : value (t) {} std::string name () const { return name (value); } static std::string name (value_type t) { std::string str; if (t & program_flow) str.append ("program_flow|"); if (t & function_arguments) str.append ("function_arguments|"); if (t & return_value) str.append ("return_value|"); if (t & data_flow) str.append ("data_flow|"); // Remove trailing pipe if (!str.empty()) str.erase (str.size() - 1); if (str.empty()) str = "(null)"; return str; } }; std::ostream& operator<< (std::ostream& os, const category& c) { return os << c.name(); } /// Specific implementation of Entry concept containing level, /// category, keyword and message typedef boost::tuple entry; /// Simple filter that implements level, category and keyword /// filtering. Will match entry tuples where the level is >= /// m_level, the category matches the m_category bitmask, and the /// keyword is either in the include list or not in the exclude list. class filter : public std::unary_function { public: filter () {} filter (level l, category c, const std::string& labels) : m_level (l), m_category (c) { configure (l, c, labels); } /// Configure level, category and keyword lists void configure (level l, category c, const std::string& labels) { m_level = l; m_category = c; configure (labels); } /// Configure the include/exclude keyword list from a pipe or /// comma delimited list of tokens. If a token begins with "!" /// it is added to the exclude list (after removing the "!" /// prefix), else it is added to the include list. void configure (const std::string& labels) { m_include.clear (); m_exclude.clear (); boost::char_separator sep ("|,"); typedef boost::tokenizer > tokenizer; tokenizer tokens (labels, sep); for (tokenizer::iterator i = tokens.begin(), e = tokens.end(); i != e; ++i) { if (i->empty()) continue; // Token starting with '!' is added to the exclude list if (*(i->begin()) == '!' && i->length() > 1) m_exclude.insert (i->substr (1)); else m_include.insert (*i); } } /// Returns true if the Entry matches (see class description), /// else false result_type operator() (const argument_type& arg) const { // If level must be >= m_level if (arg.get<0>().value < m_level.value) return false; // Category must match m_category mask else if (!(arg.get<1>().value & m_category.value)) return false; const std::string& label = arg.get<2>(); if (label.empty()) // Can we filter on an empty label? return true; // If we have an include list, the label must match else if (!m_include.empty() && m_include.find (label) == m_include.end()) return false; // If we have an exclude list, the label must NOT match else if (!m_exclude.empty() && m_exclude.find (label) != m_exclude.end()) return false; return true; } private: level m_level; category m_category; typedef std::set keyword_set; keyword_set m_include; keyword_set m_exclude; }; typedef logging::basic_file_sink file_sink; typedef logging::basic_ostream_sink ostream_sink; typedef logging::basic_logger logger; } // namespace tuple_log #endif // macro guard