Kea  2.1.7-git
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 
14 #include <exceptions/exceptions.h>
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 
21 namespace isc {
22 namespace log {
23 
28 
29 class FormatFailure : public isc::Exception {
30 public:
31  FormatFailure(const char* file, size_t line, const char* what) :
32  isc::Exception(file, line, what)
33  {}
34 };
35 
36 
41 
43 public:
44  MismatchedPlaceholders(const char* file, size_t line, const char* what) :
45  isc::Exception(file, line, what)
46  {}
47 };
48 
49 
55 void
56 checkExcessPlaceholders(std::string& message, unsigned int placeholder);
57 
64 void
65 replacePlaceholder(std::string& message, const std::string& replacement,
66  const unsigned placeholder);
67 
105 template<class Logger> class Formatter {
106 private:
110  mutable Logger* logger_;
111 
113  Severity severity_;
114 
116  boost::shared_ptr<std::string> message_;
117 
119  unsigned nextPlaceholder_;
120 
121 
122 public:
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 
173  Formatter& operator =(const Formatter& other) {
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
~Formatter()
Destructor.
Formatter(const Formatter &other)
Copy constructor.
Logger Class.
Definition: log/logger.h:141
Formatter & arg(const std::string &arg)
String version of arg.
MismatchedPlaceholders(const char *file, size_t line, const char *what)
Definition: log_formatter.h:44
Format Failure.
Definition: log_formatter.h:29
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
void replacePlaceholder(std::string &message, const string &arg, const unsigned placeholder)
The internal replacement routine.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Severity
Severity Levels.
Definition: logger_level.h:23
Formatter & arg(const Arg &value)
Replaces another placeholder.
Formatter(const Severity &severity=NONE, boost::shared_ptr< std::string > message=boost::make_shared< std::string >(), Logger *logger=NULL)
Constructor of "active" formatter.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-lfc.
isc::log::Logger logger("asiodns")
Use the ASIO logger.
Mismatched Placeholders.
Definition: log_formatter.h:42
The log message formatter.
void checkExcessPlaceholders(std::string &message, unsigned int placeholder)
Internal excess placeholder checker.
void deactivate()
Turn off the output of this logger.
FormatFailure(const char *file, size_t line, const char *what)
Definition: log_formatter.h:31