/*
* File: Logging.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Logging_h_)
#define _Logging_h_
#include <string>
#include <assert.h>
#include <stdarg.h>
/*!
* \brief Base logger class.
*
* There are two types of logging levels that are used by this class. First
* there is the filter level. Any log message that is assigned a level
* higher than the current filter level is discarded. Secondly there is the
* current output level. Log messages that do not have their own level
* use the current output level to determine if they should be shown or
* not.
*
* The two methods setFilterLevel() and setOutputLevel() set the filter
* and default output logging levels, respectively. There are corresponding
* getter methods as well. Both the filter and output levels are
* initialized to #INFO during object construction.
*
* Most use of the logger classes is expected to be through the Log
* class. It provides static logging methods that call through to a global
* singleton logger instance. There is also a Log::SetOutputLevel utility
* class that makes it extremely easiy to temporarily change the default
* output logging level.
*
* Of all the overloaded log() methods in this class, none of them are
* really expected to be reimplemented by subclasses. Instead, there is
* the single protected _log() method that takes a simple string pointer.
* The other log methods all wind up calling _log(), so it provides a
* single point to override. In fact, _log() is pure virtual, so subclasses
* must implement it.
*
* \see Log
*/
class Logger
{
public:
//! \brief Logging levels.
enum log_level_t
{
URGENT = 0, //!< The lowest level, for messages that must always be logged.
ERROR, //!< For fatal error messages.
WARNING, //!< For non-fatal warning messages.
INFO, //!< The normal log level, for status messages.
INFO2, //!< For verbose status messages.
DEBUG, //!< For internal reporting.
DEBUG2 //!< Highest log level; verbose debug logging.
};
public:
//! \brief Default constructor.
Logger() : m_filter(INFO), m_level(INFO) {}
//! \brief Destructor.
virtual ~Logger() {}
//! \name Logging levels
//@{
//! \brief Changes the logging level to \a level.
inline void setFilterLevel(log_level_t level) { m_filter = level; }
//! \brief Returns the current logging filter level.
inline log_level_t getFilterLevel() const { return m_filter; }
//! \brief Changes the logging output level to \a level.
inline void setOutputLevel(log_level_t level) { m_level = level; }
//! \brief Returns the current logging output level.
inline log_level_t getOutputLevel() const { return m_level; }
//@}
//! \name Logging
//@{
//! \brief Log with format.
virtual void log(const char * fmt, ...);
//! \brief Log a string object.
virtual void log(const std::string & msg) { log(msg.c_str()); }
//! \brief Log with format at a specific output level.
virtual void log(log_level_t level, const char * fmt, ...);
//! \brief Log a string output at a specific output level.
virtual void log(log_level_t level, const std::string & msg) { log(level, msg.c_str()); }
//! \brief Log with format using an argument list.
virtual void log(const char * fmt, va_list args);
//! \brief Log with format using an argument with a specific output level.
virtual void log(log_level_t level, const char * fmt, va_list args);
//@}
protected:
log_level_t m_filter; //!< The current logging filter level.
log_level_t m_level; //!< The current log output level.
protected:
//! \brief The base pure virtual logging function implemented by subclasses.
virtual void _log(const char * msg)=0;
};
/*!
* \brief Wraps a set of static functions for easy global logging access.
*
* This class has a set of static methods that make it easy to access a global
* logger instance without having to worry about extern symbols. It does this
* by keeping a static member variable pointing at the singleton logger instance,
* which is set with the setLogger() static method.
*
* There is also an inner utility class called SetOutputLevel that uses
* C++ scoping rules to temporarily change the output logging level. When the
* SetOutputLevel instance falls out of scope the output level is restored
* to the previous value.
*/
class Log
{
public:
//! \name Singleton logger access
//@{
//! \brief Returns the current global logger singleton.
static inline Logger * getLogger() { return s_logger; }
//! \brief Sets the global logger singleton instance.
static inline void setLogger(Logger * logger) { s_logger = logger; }
//@}
//! \name Logging
//@{
//! \brief Log with format.
static void log(const char * fmt, ...);
//! \brief Log a string object.
static void log(const std::string & msg);
//! \brief Log with format at a specific output level.
static void log(Logger::log_level_t level, const char * fmt, ...);
//! \brief Log a string output at a specific output level.
static void log(Logger::log_level_t level, const std::string & msg);
//@}
protected:
static Logger * s_logger; //!< The single global logger instance.
public:
/*!
* \brief Utility class to temporarily change the logging output level.
*
* This class will change the current logging output level of a given
* logger instance. Then when it falls out of scope it will set the
* level back to what it was originally.
*
* Use like this:
* \code
* // output level is some value here
* {
* Log::SetOutputLevel leveler(Logger::DEBUG);
* // now output level is DEBUG
* Log::log("my debug message 1");
* Log::log("my debug message 2");
* }
* // output level is restored to previous value
* \endcode
*/
class SetOutputLevel
{
public:
//! \brief Default constructor.
//!
//! Saves the current logging output level of the global logger,
//! as managed by the Log class, and sets the new level to \a level.
SetOutputLevel(Logger::log_level_t level)
: m_logger(Log::getLogger()), m_saved(Logger::INFO)
{
assert(m_logger);
m_saved = m_logger->getOutputLevel();
m_logger->setOutputLevel(level);
}
//! \brief Constructor.
//!
//! Saves the current logging output level of \a logger and sets
//! the new level to \a level.
SetOutputLevel(Logger * logger, Logger::log_level_t level)
: m_logger(logger), m_saved(logger->getOutputLevel())
{
assert(m_logger);
m_logger->setOutputLevel(level);
}
//! \brief Destructor.
//!
//! Restores the saved logging output level.
~SetOutputLevel()
{
m_logger->setOutputLevel(m_saved);
}
protected:
Logger * m_logger; //!< The logger instance we're controlling.
Logger::log_level_t m_saved; //!< Original logging output level.
};
};
/*!
* \brief Simple logger that writes to stdout.
*/
class StdoutLogger : public Logger
{
protected:
//! \brief Logs the message to stdout.
virtual void _log(const char * msg);
};
#endif // _Logging_h_