log_formatter.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. #ifndef __LOG_FORMATTER_H
  15. #define __LOG_FORMMATER_H
  16. #include <cstddef>
  17. #include <string>
  18. #include <iostream>
  19. #include <exceptions/exceptions.h>
  20. #include <boost/lexical_cast.hpp>
  21. #include <log/logger_level.h>
  22. namespace isc {
  23. namespace log {
  24. /// \brief Format Failure
  25. ///
  26. /// This exception is used to wrap a bad_lexical_cast exception thrown during
  27. /// formatting an argument.
  28. class FormatFailure : public isc::Exception {
  29. public:
  30. FormatFailure(const char* file, size_t line, const char* what) :
  31. isc::Exception(file, line, what)
  32. {}
  33. };
  34. ///
  35. /// \brief The internal replacement routine
  36. ///
  37. /// This is used internally by the Formatter. Replaces a placeholder
  38. /// in the message by replacement. If the placeholder is not found,
  39. /// it adds a complain at the end.
  40. void
  41. replacePlaceholder(std::string* message, const std::string& replacement,
  42. const unsigned placeholder);
  43. ///
  44. /// \brief The log message formatter
  45. ///
  46. /// This class allows us to format logging messages conveniently. We
  47. /// call something like logger.warn(WARN_MSG).arg(15).arg(dnsMsg). This
  48. /// outputs some text with placeholders replaced by the arguments, if
  49. /// the logging verbosity is at WARN level or more.
  50. ///
  51. /// To make this work, we use the Formatter. The warn (or whatever logging
  52. /// function) returns a Formatter object. That one holds the string to be
  53. /// output with the placeholders. It also remembers if there should be any
  54. /// output at all (eg. if the logging is enabled for this level). When there's
  55. /// no .arg call on the object, it is destroyed right away and we use the
  56. /// destructor to output the text (but only in case we should output anything).
  57. ///
  58. /// If there's an .arg call, we return reference to the same object, so another
  59. /// .arg can be called on it. After the last .arg call is done, the object is
  60. /// destroyed and, again, we can produce the output.
  61. ///
  62. /// Of course, if the logging is turned off, we don't bother with any replacing
  63. /// and just return.
  64. ///
  65. /// User of logging code should not really care much about this class, only
  66. /// call the .arg method to generate the correct output.
  67. ///
  68. /// The class is a template to allow easy testing. Also, we want everything
  69. /// here in the header anyway and it doesn't depend on the details of what
  70. /// Logger really is, so it doesn't hurt anything.
  71. ///
  72. /// Also, if you are interested in the internals, you might find the copy
  73. /// constructor a bit strange. It deactivates the original formatter. We don't
  74. /// really want to support copying of the Formatter by user, but C++ needs a
  75. /// copy constructor when returning from the logging functions, so we need one.
  76. /// And if we did not deactivate the original Formatter, that one would get
  77. /// destroyed before any call to .arg, producing an output, and then the one
  78. /// the .arg calls are called on would get destroyed as well, producing output
  79. /// again. So, think of this behaviour as soul moving from one to another.
  80. template<class Logger> class Formatter {
  81. private:
  82. /// \brief The logger we will use to output the final message.
  83. ///
  84. /// If NULL, we are not active and should not produce anything.
  85. mutable Logger* logger_;
  86. /// \brief Message severity
  87. Severity severity_;
  88. /// \brief The messages with %1, %2... placeholders
  89. std::string* message_;
  90. /// \brief Which will be the next placeholder to replace
  91. unsigned nextPlaceholder_;
  92. public:
  93. /// \brief Constructor of "active" formatter
  94. ///
  95. /// This will create a formatter. If the arguments are set, it
  96. /// will be active (will produce output). If you leave them all as NULL,
  97. /// it will create an inactive Formatter -- one that'll produce no output.
  98. ///
  99. /// It is not expected to be called by user of logging system directly.
  100. ///
  101. /// \param severity The severity of the message (DEBUG, ERROR etc.)
  102. /// \param message The message with placeholders. We take ownership of
  103. /// it and we will modify the string. Must not be NULL unless
  104. /// logger is also NULL, but it's not checked.
  105. /// \param logger The logger where the final output will go, or NULL
  106. /// if no output is wanted.
  107. Formatter(const Severity& severity = NONE, std::string* message = NULL,
  108. Logger* logger = NULL) :
  109. logger_(logger), severity_(severity), message_(message),
  110. nextPlaceholder_(0)
  111. {
  112. }
  113. /// \brief Copy constructor
  114. ///
  115. /// "Control" is passed to the created object in that it is the created object
  116. /// that will have responsibility for outputting the formatted message - the
  117. /// object being copied relinquishes that responsibility.
  118. Formatter(const Formatter& other) :
  119. logger_(other.logger_), severity_(other.severity_),
  120. message_(other.message_), nextPlaceholder_(other.nextPlaceholder_)
  121. {
  122. other.logger_ = NULL;
  123. }
  124. /// \brief Destructor.
  125. //
  126. /// This is the place where output happens if the formatter is active.
  127. ~ Formatter() {
  128. if (logger_) {
  129. logger_->output(severity_, *message_);
  130. delete message_;
  131. }
  132. }
  133. /// \brief Assignment operator
  134. ///
  135. /// Essentially the same function as the assignment operator - the object being
  136. /// assigned to takes responsibility for outputting the message.
  137. Formatter& operator =(const Formatter& other) {
  138. if (&other != this) {
  139. logger_ = other.logger_;
  140. severity_ = other.severity_;
  141. message_ = other.message_;
  142. nextPlaceholder_ = other.nextPlaceholder_;
  143. other.logger_ = NULL;
  144. }
  145. return *this;
  146. }
  147. /// \brief Replaces another placeholder
  148. ///
  149. /// Replaces another placeholder and returns a new formatter with it.
  150. /// Deactivates the current formatter. In case the formatter is not active,
  151. /// only produces another inactive formatter.
  152. ///
  153. /// \param value The argument to place into the placeholder.
  154. template<class Arg> Formatter& arg(const Arg& value) {
  155. if (logger_) {
  156. try {
  157. return (arg(boost::lexical_cast<std::string>(value)));
  158. } catch (const boost::bad_lexical_cast& ex) {
  159. // A bad_lexical_cast during a conversion to a string is
  160. // *extremely* unlikely to fail. However, there is nothing
  161. // in the documentation that rules it out, so we need to handle
  162. // it. As it is a potentially very serious problem, throw the
  163. // exception detailing the problem with as much information as
  164. // we can. (Note that this does not include 'value' -
  165. // boost::lexical_cast failed to convert it to a string, so an
  166. // attempt to do so here would probably fail as well.)
  167. isc_throw(FormatFailure, "bad_lexical_cast in call to "
  168. "Formatter::arg(): " << ex.what());
  169. }
  170. } else {
  171. return (*this);
  172. }
  173. }
  174. /// \brief String version of arg.
  175. ///
  176. /// \param arg The text to place into the placeholder.
  177. Formatter& arg(const std::string& arg) {
  178. if (logger_) {
  179. // Note that this method does a replacement and returns the
  180. // modified string. If there are multiple invocations of arg() (e.g.
  181. // logger.info(msgid).arg(xxx).arg(yyy)...), each invocation
  182. // operates on the string returned by the previous one. This
  183. // sequential operation means that if we had a message like "%1 %2",
  184. // and called .arg("%2").arg(42), we would get "42 42"; the first
  185. // call replaces the %1" with "%2" and the second replaces all
  186. // occurrences of "%2" with 42. (Conversely, the sequence
  187. // .arg(42).arg("%1") would return "42 %1" - there are no recursive
  188. // replacements).
  189. replacePlaceholder(message_, arg, ++nextPlaceholder_ );
  190. }
  191. return (*this);
  192. }
  193. };
  194. }
  195. }
  196. #endif