Kea 2.7.5
log_formatter.h
Go to the documentation of this file.
1// Copyright (C) 2011-2020 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 <log/logger_level.h>
16
17#include <boost/make_shared.hpp>
18#include <boost/shared_ptr.hpp>
19#include <boost/lexical_cast.hpp>
20
21namespace isc {
22namespace log {
23
28
30public:
31 FormatFailure(const char* file, size_t line, const char* what) :
32 isc::Exception(file, line, what)
33 {}
34};
35
36
41
43public:
44 MismatchedPlaceholders(const char* file, size_t line, const char* what) :
45 isc::Exception(file, line, what)
46 {}
47};
48
49
55void
56checkExcessPlaceholders(std::string& message, unsigned int placeholder);
57
64void
65replacePlaceholder(std::string& message, const std::string& replacement,
66 const unsigned placeholder);
67
105template<class Logger> class Formatter {
106private:
110 mutable Logger* logger_;
111
113 Severity severity_;
114
116 boost::shared_ptr<std::string> message_;
117
119 unsigned nextPlaceholder_;
120
121
122public:
137 Formatter(const Severity& severity = NONE,
138 boost::shared_ptr<std::string> message = boost::make_shared<std::string>(),
139 Logger* logger = NULL) :
140 logger_(logger), severity_(severity), message_(message),
141 nextPlaceholder_(0) {
142 }
143
149 Formatter(const Formatter& other) :
150 logger_(other.logger_), severity_(other.severity_),
151 message_(other.message_), nextPlaceholder_(other.nextPlaceholder_) {
152 other.logger_ = NULL;
153 }
154
156 //
159 if (logger_) {
160 try {
161 checkExcessPlaceholders(*message_, ++nextPlaceholder_);
162 logger_->output(severity_, *message_);
163 } catch (...) {
164 // Catch and ignore all exceptions here.
165 }
166 }
167 }
168
174 if (&other != this) {
175 logger_ = other.logger_;
176 severity_ = other.severity_;
177 message_ = other.message_;
178 nextPlaceholder_ = other.nextPlaceholder_;
179 other.logger_ = NULL;
180 }
181
182 return *this;
183 }
184
192 template<class Arg> Formatter& arg(const Arg& value) {
193 if (logger_) {
194 try {
195 return (arg(boost::lexical_cast<std::string>(value)));
196 } catch (const boost::bad_lexical_cast& ex) {
197 // The formatting of the log message got wrong, we don't want
198 // to output it.
199 deactivate();
200 // A bad_lexical_cast during a conversion to a string is
201 // *extremely* unlikely to fail. However, there is nothing
202 // in the documentation that rules it out, so we need to handle
203 // it. As it is a potentially very serious problem, throw the
204 // exception detailing the problem with as much information as
205 // we can. (Note that this does not include 'value' -
206 // boost::lexical_cast failed to convert it to a string, so an
207 // attempt to do so here would probably fail as well.)
208 isc_throw(FormatFailure, "bad_lexical_cast in call to "
209 "Formatter::arg(): " << ex.what());
210 }
211 } else {
212 return (*this);
213 }
214 }
215
219 Formatter& arg(const std::string& arg) {
220 if (logger_) {
221 // Note that this method does a replacement and returns the
222 // modified string. If there are multiple invocations of arg() (e.g.
223 // logger.info(msgid).arg(xxx).arg(yyy)...), each invocation
224 // operates on the string returned by the previous one. This
225 // sequential operation means that if we had a message like "%1 %2",
226 // and called .arg("%2").arg(42), we would get "42 42"; the first
227 // call replaces the %1" with "%2" and the second replaces all
228 // occurrences of "%2" with 42. (Conversely, the sequence
229 // .arg(42).arg("%1") would return "42 %1" - there are no recursive
230 // replacements).
231 try {
232 replacePlaceholder(*message_, arg, ++nextPlaceholder_);
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 message_.reset();
255 logger_ = NULL;
256 }
257 }
258};
259
260} // namespace log
261} // namespace isc
262
263#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)
The log message formatter.
Formatter(const Formatter &other)
Copy constructor.
~Formatter()
Destructor.
Formatter & arg(const Arg &value)
Replaces another placeholder.
void deactivate()
Turn off the output of this logger.
Formatter & arg(const std::string &arg)
String version of arg.
Formatter & operator=(const Formatter &other)
Assignment operator.
Formatter(const Severity &severity=NONE, boost::shared_ptr< std::string > message=boost::make_shared< std::string >(), Logger *logger=NULL)
Constructor of "active" formatter.
Logger Class.
Definition log/logger.h:142
Mismatched Placeholders.
MismatchedPlaceholders(const char *file, size_t line, const char *what)
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void checkExcessPlaceholders(std::string &message, unsigned int placeholder)
Internal excess placeholder checker.
void replacePlaceholder(std::string &message, const string &arg, const unsigned placeholder)
The internal replacement routine.
Severity
Severity Levels.
Defines the logger used by the top-level component of kea-lfc.