Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef __LOGGER_H
16 : : #define __LOGGER_H
17 : :
18 : : #include <cassert>
19 : : #include <cstdlib>
20 : : #include <string>
21 : : #include <cstring>
22 : :
23 : : #include <exceptions/exceptions.h>
24 : : #include <log/logger_level.h>
25 : : #include <log/message_types.h>
26 : : #include <log/log_formatter.h>
27 : :
28 : :
29 : : namespace isc {
30 : : namespace log {
31 : :
32 : : /// \page LoggingApi Logging API
33 : : /// \section LoggingApiOverview Overview
34 : : /// BIND 10 logging uses the concepts of the widely-used Java logging
35 : : /// package log4j (http://logging.apache.log/log4j), albeit implemented
36 : : /// in C++ using an open-source port. Features of the system are:
37 : : ///
38 : : /// - Within the code objects - known as loggers - can be created and
39 : : /// used to log messages. These loggers have names; those with the
40 : : /// same name share characteristics (such as output destination).
41 : : /// - Loggers have a hierarchical relationship, with each logger being
42 : : /// the child of another logger, except for the top of the hierarchy, the
43 : : /// root logger. If a logger does not log a message, it is passed to the
44 : : /// parent logger.
45 : : /// - Messages can be logged at severity levels of FATAL, ERROR, WARN, INFO
46 : : /// or DEBUG. The DEBUG level has further sub-levels numbered 0 (least
47 : : /// informative) to 99 (most informative).
48 : : /// - Each logger has a severity level set associated with it. When a
49 : : /// message is logged, it is output only if it is logged at a level equal
50 : : /// to the logger severity level or greater, e.g. if the logger's severity
51 : : /// is WARN, only messages logged at WARN, ERROR or FATAL will be output.
52 : : ///
53 : : /// \section LoggingApiLoggerNames BIND 10 Logger Names
54 : : /// Within BIND 10, the root logger root logger is given the name of the
55 : : /// program (via the stand-alone function setRootLoggerName()). Other loggers
56 : : /// are children of the root logger and are named "<program>.<sublogger>".
57 : : /// This name appears in logging output, allowing users to identify both
58 : : /// the BIND 10 program and the component within the program that generated
59 : : /// the message.
60 : : ///
61 : : /// When creating a logger, the abbreviated name "<sublogger>" can be used;
62 : : /// the program name will be prepended to it when the logger is created.
63 : : /// In this way, individual libraries can have their own loggers without
64 : : /// worrying about the program in which they are used, but:
65 : : /// - The origin of the message will be clearly identified.
66 : : /// - The same component can have different options (e.g. logging severity)
67 : : /// in different programs at the same time.
68 : : ///
69 : : /// \section LoggingApiLoggingMessages Logging Messages
70 : : /// Instead of embedding the text of messages within the code, each message
71 : : /// is referred to using a symbolic name. The logging code uses this name as
72 : : /// a key in a dictionary from which the message text is obtained. Such a
73 : : /// system allows for the optional replacement of message text at run time.
74 : : /// More details about the message dictionary (and the compiler used to create
75 : : /// the symbol definitions) can be found in other modules in the src/lib/log
76 : : /// directory.
77 : : ///
78 : : /// \section LoggingApiImplementationIssues Implementation Issues
79 : : /// Owing to the way that the logging is implemented, notably that loggers can
80 : : /// be declared as static external objects, there is a restriction on the
81 : : /// length of the name of a logger component (i.e. the length of
82 : : /// the string passed to the Logger constructor) to a maximum of 31 characters.
83 : : /// There is no reason for this particular value other than limiting the amount
84 : : /// of memory used. It is defined by the constant Logger::MAX_LOGGER_NAME_SIZE,
85 : : /// and can be made larger (or smaller) if so desired. Note however, using a
86 : : /// logger name larger than this limit will cause an assertion failure.
87 : :
88 : : class LoggerImpl; // Forward declaration of the implementation class
89 : :
90 : : /// \brief Logging Not Initialized
91 : : ///
92 : : /// Exception thrown if an attempt is made to access a logging function
93 : : /// if the logging system has not been initialized.
94 : 2 : class LoggingNotInitialized : public isc::Exception {
95 : : public:
96 : : LoggingNotInitialized(const char* file, size_t line, const char* what) :
97 : 4 : isc::Exception(file, line, what)
98 : : {}
99 : : };
100 : :
101 : : /// \brief Logger Class
102 : : ///
103 : : /// This class is the main class used for logging. Use comprises:
104 : : ///
105 : : /// 1. Constructing a logger by instantiating it with a specific name. (If the
106 : : /// same logger is in multiple functions within a file, overhead can be
107 : : /// minimised by declaring it as a file-wide static variable.)
108 : : /// 2. Using the error(), info() etc. methods to log an error. (However, it is
109 : : /// recommended to use the LOG_ERROR, LOG_INFO etc. macros defined in macros.h.
110 : : /// These will avoid the potentially-expensive evaluation of arguments if the
111 : : /// severity is such that the message will be suppressed.)
112 : :
113 : : class Logger {
114 : : public:
115 : : /// Maximum size of a logger name
116 : : static const size_t MAX_LOGGER_NAME_SIZE = 31;
117 : :
118 : : /// \brief Constructor
119 : : ///
120 : : /// Creates/attaches to a logger of a specific name.
121 : : ///
122 : : /// \param name Name of the logger. If the name is that of the root name,
123 : : /// this creates an instance of the root logger; otherwise it creates a
124 : : /// child of the root logger.
125 : : ///
126 : : /// \note The name of the logger may be no longer than MAX_LOGGER_NAME_SIZE
127 : : /// else the program will halt with an assertion failure. This restriction
128 : : /// allows loggers to be declared statically: the name is stored in a
129 : : /// fixed-size array to avoid the need to allocate heap storage during
130 : : /// program initialization (which causes problems on some operating
131 : : /// systems).
132 : : ///
133 : : /// \note Note also that there is no constructor taking a std::string. This
134 : : /// minimises the possibility of initializing a static logger with a
135 : : /// string, so leading to problems mentioned above.
136 : 891 : Logger(const char* name) : loggerptr_(NULL) {
137 [ - + ]: 250 : assert(std::strlen(name) < sizeof(name_));
138 : : // Do the copy. Note that the assertion above has checked that the
139 : : // contents of "name" and a trailing null will fit within the space
140 : : // allocated for name_, so we could use strcpy here and be safe.
141 : : // However, a bit of extra paranoia doesn't hurt.
142 : 891 : std::strncpy(name_, name, sizeof(name_));
143 [ - + ][ - + ]: 891 : assert(name_[sizeof(name_) - 1] == '\0');
144 : 57 : }
145 : :
146 : : /// \brief Destructor
147 : : virtual ~Logger();
148 : :
149 : : /// \brief The formatter used to replace placeholders
150 : : typedef isc::log::Formatter<Logger> Formatter;
151 : :
152 : : /// \brief Get Name of Logger
153 : : ///
154 : : /// \return The full name of the logger (including the root name)
155 : : virtual std::string getName();
156 : :
157 : : /// \brief Set Severity Level for Logger
158 : : ///
159 : : /// Sets the level at which this logger will log messages. If none is set,
160 : : /// the level is inherited from the parent.
161 : : ///
162 : : /// \param severity Severity level to log
163 : : /// \param dbglevel If the severity is DEBUG, this is the debug level.
164 : : /// This can be in the range 1 to 100 and controls the verbosity. A value
165 : : /// outside these limits is silently coerced to the nearest boundary.
166 : : virtual void setSeverity(isc::log::Severity severity, int dbglevel = 1);
167 : :
168 : : /// \brief Get Severity Level for Logger
169 : : ///
170 : : /// \return The current logging level of this logger. In most cases though,
171 : : /// the effective logging level is what is required.
172 : : virtual isc::log::Severity getSeverity();
173 : :
174 : : /// \brief Get Effective Severity Level for Logger
175 : : ///
176 : : /// \return The effective severity level of the logger. This is the same
177 : : /// as getSeverity() if the logger has a severity level set, but otherwise
178 : : /// is the severity of the parent.
179 : : virtual isc::log::Severity getEffectiveSeverity();
180 : :
181 : : /// \brief Return DEBUG Level
182 : : ///
183 : : /// \return Current setting of debug level. This is returned regardless of
184 : : /// whether the severity is set to debug.
185 : : virtual int getDebugLevel();
186 : :
187 : : /// \brief Get Effective Debug Level for Logger
188 : : ///
189 : : /// \return The effective debug level of the logger. This is the same
190 : : /// as getDebugLevel() if the logger has a debug level set, but otherwise
191 : : /// is the debug level of the parent.
192 : : virtual int getEffectiveDebugLevel();
193 : :
194 : : /// \brief Returns if Debug Message Should Be Output
195 : : ///
196 : : /// \param dbglevel Level for which debugging is checked. Debugging is
197 : : /// enabled only if the logger has DEBUG enabled and if the dbglevel
198 : : /// checked is less than or equal to the debug level set for the logger.
199 : : virtual bool isDebugEnabled(int dbglevel = MIN_DEBUG_LEVEL);
200 : :
201 : : /// \brief Is INFO Enabled?
202 : : virtual bool isInfoEnabled();
203 : :
204 : : /// \brief Is WARNING Enabled?
205 : : virtual bool isWarnEnabled();
206 : :
207 : : /// \brief Is ERROR Enabled?
208 : : virtual bool isErrorEnabled();
209 : :
210 : : /// \brief Is FATAL Enabled?
211 : : virtual bool isFatalEnabled();
212 : :
213 : : /// \brief Output Debug Message
214 : : ///
215 : : /// \param dbglevel Debug level, ranging between 0 and 99. Higher numbers
216 : : /// are used for more verbose output.
217 : : /// \param ident Message identification.
218 : : Formatter debug(int dbglevel, const MessageID& ident);
219 : :
220 : : /// \brief Output Informational Message
221 : : ///
222 : : /// \param ident Message identification.
223 : : Formatter info(const MessageID& ident);
224 : :
225 : : /// \brief Output Warning Message
226 : : ///
227 : : /// \param ident Message identification.
228 : : Formatter warn(const MessageID& ident);
229 : :
230 : : /// \brief Output Error Message
231 : : ///
232 : : /// \param ident Message identification.
233 : : Formatter error(const MessageID& ident);
234 : :
235 : : /// \brief Output Fatal Message
236 : : ///
237 : : /// \param ident Message identification.
238 : : Formatter fatal(const MessageID& ident);
239 : :
240 : : /// \brief Equality
241 : : ///
242 : : /// Check if two instances of this logger refer to the same stream.
243 : : ///
244 : : /// \return true if the logger objects are instances of the same logger.
245 : : bool operator==(Logger& other);
246 : :
247 : : private:
248 : : friend class isc::log::Formatter<Logger>;
249 : :
250 : : /// \brief Raw output function
251 : : ///
252 : : /// This is used by the formatter to output formatted output.
253 : : ///
254 : : /// \param severity Severity of the message being output.
255 : : /// \param message Text of the message to be output.
256 : : void output(const Severity& severity, const std::string& message);
257 : :
258 : : /// \brief Copy Constructor
259 : : ///
260 : : /// Disabled (marked private) as it makes no sense to copy the logger -
261 : : /// just create another one of the same name.
262 : : Logger(const Logger&);
263 : :
264 : : /// \brief Assignment Operator
265 : : ///
266 : : /// Disabled (marked private) as it makes no sense to copy the logger -
267 : : /// just create another one of the same name.
268 : : Logger& operator=(const Logger&);
269 : :
270 : : /// \brief Initialize Implementation
271 : : ///
272 : : /// Returns the logger pointer. If not yet set, the implementation class is
273 : : /// initialized.
274 : : ///
275 : : /// The main reason for this is to allow loggers to be declared statically
276 : : /// before the underlying logging system is initialized. However, any
277 : : /// attempt to access a logging method on any logger before initialization -
278 : : /// regardless of whether is is statically or automatically declared - will
279 : : /// cause a "LoggingNotInitialized" exception to be thrown.
280 : : ///
281 : : /// \return Returns pointer to implementation
282 : 162158 : LoggerImpl* getLoggerPtr() {
283 [ + + ]: 162158 : if (!loggerptr_) {
284 : 171 : initLoggerImpl();
285 : : }
286 : 162156 : return (loggerptr_);
287 : : }
288 : :
289 : : /// \brief Initialize Underlying Implementation and Set loggerptr_
290 : : void initLoggerImpl();
291 : :
292 : : LoggerImpl* loggerptr_; ///< Pointer to underlying logger
293 : : char name_[MAX_LOGGER_NAME_SIZE + 1]; ///< Copy of the logger name
294 : : };
295 : :
296 : : } // namespace log
297 : : } // namespace isc
298 : :
299 : :
300 : : #endif // __LOGGER_H
|