summaryrefslogtreecommitdiffstats
path: root/common/Logging.h
blob: a8e7beda12513acbc01d32d137e92b29bdc1b3ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 * 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_