Kea 1.5.0
log_formatter.h
Go to the documentation of this file.
1// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#ifndef LOG_FORMATTER_H
8#define LOG_FORMATTER_H
9
10#include <cstddef>
11#include <string>
12#include <iostream>
13
15#include <boost/lexical_cast.hpp>
16#include <log/logger_level.h>
17
18namespace isc {
19namespace log {
20
25
27public:
28 FormatFailure(const char* file, size_t line, const char* what) :
29 isc::Exception(file, line, what)
30 {}
31};
32
33
38
40public:
41 MismatchedPlaceholders(const char* file, size_t line, const char* what) :
42 isc::Exception(file, line, what)
43 {}
44};
45
46
52void
53checkExcessPlaceholders(std::string* message, unsigned int placeholder);
54
61void
62replacePlaceholder(std::string* message, const std::string& replacement,
63 const unsigned placeholder);
64
102template<class Logger> class Formatter {
103private:
107 mutable Logger* logger_;
108
110 Severity severity_;
111
113 std::string* message_;
114
116 unsigned nextPlaceholder_;
117
118
119public:
134 Formatter(const Severity& severity = NONE, std::string* message = NULL,
135 Logger* logger = NULL) :
136 logger_(logger), severity_(severity), message_(message),
137 nextPlaceholder_(0)
138 {
139 }
140
146 Formatter(const Formatter& other) :
147 logger_(other.logger_), severity_(other.severity_),
148 message_(other.message_), nextPlaceholder_(other.nextPlaceholder_)
149 {
150 other.logger_ = NULL;
151 }
152
154 //
156 ~ Formatter() {
157 if (logger_) {
158 try {
159 checkExcessPlaceholders(message_, ++nextPlaceholder_);
160 logger_->output(severity_, *message_);
161 } catch (...) {
162 // Catch and ignore all exceptions here.
163 }
164 delete message_;
165 }
166 }
167
173 if (&other != this) {
174 logger_ = other.logger_;
175 severity_ = other.severity_;
176 message_ = other.message_;
177 nextPlaceholder_ = other.nextPlaceholder_;
178 other.logger_ = NULL;
179 }
180
181 return *this;
182 }
183
191 template<class Arg> Formatter& arg(const Arg& value) {
192 if (logger_) {
193 try {
194 return (arg(boost::lexical_cast<std::string>(value)));
195 } catch (const boost::bad_lexical_cast& ex) {
196 // The formatting of the log message got wrong, we don't want
197 // to output it.
198 deactivate();
199 // A bad_lexical_cast during a conversion to a string is
200 // *extremely* unlikely to fail. However, there is nothing
201 // in the documentation that rules it out, so we need to handle
202 // it. As it is a potentially very serious problem, throw the
203 // exception detailing the problem with as much information as
204 // we can. (Note that this does not include 'value' -
205 // boost::lexical_cast failed to convert it to a string, so an
206 // attempt to do so here would probably fail as well.)
207 isc_throw(FormatFailure, "bad_lexical_cast in call to "
208 "Formatter::arg(): " << ex.what());
209 }
210 } else {
211 return (*this);
212 }
213 }
214
218 Formatter& arg(const std::string& arg) {
219 if (logger_) {
220 // Note that this method does a replacement and returns the
221 // modified string. If there are multiple invocations of arg() (e.g.
222 // logger.info(msgid).arg(xxx).arg(yyy)...), each invocation
223 // operates on the string returned by the previous one. This
224 // sequential operation means that if we had a message like "%1 %2",
225 // and called .arg("%2").arg(42), we would get "42 42"; the first
226 // call replaces the %1" with "%2" and the second replaces all
227 // occurrences of "%2" with 42. (Conversely, the sequence
228 // .arg(42).arg("%1") would return "42 %1" - there are no recursive
229 // replacements).
230 try {
231 replacePlaceholder(message_, arg, ++nextPlaceholder_ );
232 }
233 catch (...) {
234 // Something went wrong here, the log message is broken, so
235 // we don't want to output it, nor we want to check all the
236 // placeholders were used (because they won't be).
237 deactivate();
238 throw;
239 }
240 }
241 return (*this);
242 }
243
252 void deactivate() {
253 if (logger_) {
254 delete message_;
255 message_ = NULL;
256 logger_ = NULL;
257 }
258 }
259};
260
261}
262}
263
264#endif
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
FormatFailure(const char *file, size_t line, const char *what)
Definition: log_formatter.h:28
The log message formatter.
Formatter(const Formatter &other)
Copy constructor.
Formatter & arg(const Arg &value)
Replaces another placeholder.
void deactivate()
Turn off the output of this logger.
Formatter(const Severity &severity=NONE, std::string *message=NULL, Logger *logger=NULL)
Constructor of "active" formatter.
Formatter & arg(const std::string &arg)
String version of arg.
Formatter & operator=(const Formatter &other)
Assignment operator.
Logger Class.
Definition: log/logger.h:143
Mismatched Placeholders.
Definition: log_formatter.h:39
MismatchedPlaceholders(const char *file, size_t line, const char *what)
Definition: log_formatter.h:41
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void replacePlaceholder(string *message, const string &arg, const unsigned placeholder)
The internal replacement routine.
Severity
Severity Levels.
Definition: logger_level.h:23
void checkExcessPlaceholders(string *message, unsigned int placeholder)
Internal excess placeholder checker.
Defines the logger used by the top-level component of kea-dhcp-ddns.