log_formatter.h 7.4 KB

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