1/*
2 * File:	Logging.h
3 *
4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5 * See included license file for license details.
6 */
7#if !defined(_Logging_h_)
8#define _Logging_h_
9
10#include <string>
11#include <assert.h>
12#include <stdarg.h>
13
14/*!
15 * \brief Base logger class.
16 *
17 * There are two types of logging levels that are used by this class. First
18 * there is the filter level. Any log message that is assigned a level
19 * higher than the current filter level is discarded. Secondly there is the
20 * current output level. Log messages that do not have their own level
21 * use the current output level to determine if they should be shown or
22 * not.
23 *
24 * The two methods setFilterLevel() and setOutputLevel() set the filter
25 * and default output logging levels, respectively. There are corresponding
26 * getter methods as well. Both the filter and output levels are
27 * initialized to #INFO during object construction.
28 *
29 * Most use of the logger classes is expected to be through the Log
30 * class. It provides static logging methods that call through to a global
31 * singleton logger instance. There is also a Log::SetOutputLevel utility
32 * class that makes it extremely easiy to temporarily change the default
33 * output logging level.
34 *
35 * Of all the overloaded log() methods in this class, none of them are
36 * really expected to be reimplemented by subclasses. Instead, there is
37 * the single protected _log() method that takes a simple string pointer.
38 * The other log methods all wind up calling _log(), so it provides a
39 * single point to override. In fact, _log() is pure virtual, so subclasses
40 * must implement it.
41 *
42 * \see Log
43 */
44class Logger
45{
46public:
47	//! \brief Logging levels.
48	enum log_level_t
49	{
50		URGENT = 0,	//!< The lowest level, for messages that must always be logged.
51		ERROR,		//!< For fatal error messages.
52		WARNING,	//!< For non-fatal warning messages.
53		INFO,		//!< The normal log level, for status messages.
54		INFO2,		//!< For verbose status messages.
55		DEBUG,		//!< For internal reporting.
56		DEBUG2		//!< Highest log level; verbose debug logging.
57	};
58
59public:
60	//! \brief Default constructor.
61	Logger() : m_filter(INFO), m_level(INFO) {}
62
63	//! \brief Destructor.
64	virtual ~Logger() {}
65
66	//! \name Logging levels
67	//@{
68	//! \brief Changes the logging level to \a level.
69	inline void setFilterLevel(log_level_t level) { m_filter = level; }
70
71	//! \brief Returns the current logging filter level.
72	inline log_level_t getFilterLevel() const { return m_filter; }
73
74	//! \brief Changes the logging output level to \a level.
75	inline void setOutputLevel(log_level_t level) { m_level = level; }
76
77	//! \brief Returns the current logging output level.
78	inline log_level_t getOutputLevel() const { return m_level; }
79	//@}
80
81	//! \name Logging
82	//@{
83	//! \brief Log with format.
84	virtual void log(const char * fmt, ...);
85
86	//! \brief Log a string object.
87	virtual void log(const std::string & msg) { log(msg.c_str()); }
88
89	//! \brief Log with format at a specific output level.
90	virtual void log(log_level_t level, const char * fmt, ...);
91
92	//! \brief Log a string output at a specific output level.
93	virtual void log(log_level_t level, const std::string & msg) { log(level, msg.c_str()); }
94
95	//! \brief Log with format using an argument list.
96	virtual void log(const char * fmt, va_list args);
97
98	//! \brief Log with format using an argument with a specific output level.
99	virtual void log(log_level_t level, const char * fmt, va_list args);
100	//@}
101
102protected:
103	log_level_t m_filter;	//!< The current logging filter level.
104	log_level_t m_level;	//!< The current log output level.
105
106protected:
107	//! \brief The base pure virtual logging function implemented by subclasses.
108	virtual void _log(const char * msg)=0;
109};
110
111/*!
112 * \brief Wraps a set of static functions for easy global logging access.
113 *
114 * This class has a set of static methods that make it easy to access a global
115 * logger instance without having to worry about extern symbols. It does this
116 * by keeping a static member variable pointing at the singleton logger instance,
117 * which is set with the setLogger() static method.
118 *
119 * There is also an inner utility class called SetOutputLevel that uses
120 * C++ scoping rules to temporarily change the output logging level. When the
121 * SetOutputLevel instance falls out of scope the output level is restored
122 * to the previous value.
123 */
124class Log
125{
126public:
127	//! \name Singleton logger access
128	//@{
129	//! \brief Returns the current global logger singleton.
130	static inline Logger * getLogger() { return s_logger; }
131
132	//! \brief Sets the global logger singleton instance.
133	static inline void setLogger(Logger * logger) { s_logger = logger; }
134	//@}
135
136	//! \name Logging
137	//@{
138	//! \brief Log with format.
139	static void log(const char * fmt, ...);
140
141	//! \brief Log a string object.
142	static void log(const std::string & msg);
143
144	//! \brief Log with format at a specific output level.
145	static void log(Logger::log_level_t level, const char * fmt, ...);
146
147	//! \brief Log a string output at a specific output level.
148	static void log(Logger::log_level_t level, const std::string & msg);
149	//@}
150
151protected:
152	static Logger * s_logger;	//!< The single global logger instance.
153
154public:
155	/*!
156	 * \brief Utility class to temporarily change the logging output level.
157	 *
158	 * This class will change the current logging output level of a given
159	 * logger instance. Then when it falls out of scope it will set the
160	 * level back to what it was originally.
161	 *
162	 * Use like this:
163	 * \code
164	 *		// output level is some value here
165	 *		{
166	 *			Log::SetOutputLevel leveler(Logger::DEBUG);
167	 *			// now output level is DEBUG
168	 *			Log::log("my debug message 1");
169	 *			Log::log("my debug message 2");
170	 *		}
171	 *		// output level is restored to previous value
172	 * \endcode
173	 */
174	class SetOutputLevel
175	{
176	public:
177		//! \brief Default constructor.
178		//!
179		//! Saves the current logging output level of the global logger,
180		//! as managed by the Log class, and sets the new level to \a level.
181		SetOutputLevel(Logger::log_level_t level)
182		:	m_logger(Log::getLogger()), m_saved(Logger::INFO)
183		{
184			assert(m_logger);
185			m_saved = m_logger->getOutputLevel();
186			m_logger->setOutputLevel(level);
187		}
188
189		//! \brief Constructor.
190		//!
191		//! Saves the current logging output level of \a logger and sets
192		//! the new level to \a level.
193		SetOutputLevel(Logger * logger, Logger::log_level_t level)
194		:	m_logger(logger), m_saved(logger->getOutputLevel())
195		{
196			assert(m_logger);
197			m_logger->setOutputLevel(level);
198		}
199
200		//! \brief Destructor.
201		//!
202		//! Restores the saved logging output level.
203		~SetOutputLevel()
204		{
205			m_logger->setOutputLevel(m_saved);
206		}
207
208	protected:
209		Logger * m_logger;	//!< The logger instance we're controlling.
210		Logger::log_level_t m_saved;	//!< Original logging output level.
211	};
212
213};
214
215
216/*!
217 * \brief Simple logger that writes to stdout.
218 */
219class StdoutLogger : public Logger
220{
221protected:
222	//! \brief Logs the message to stdout.
223	virtual void _log(const char * msg);
224};
225
226#endif // _Logging_h_
227