You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
4.5 KiB

2 months ago
  1. /**
  2. * @file formatter.h
  3. * @author Harold Bruintjes <h.bruintjes@cs.rwth-aachen.de>
  4. *
  5. * Define the Formatter class, used to format output of a sink
  6. */
  7. #pragma once
  8. #include <string>
  9. #include <tuple>
  10. namespace l3pp {
  11. /**
  12. * Formats a log messages. This is a base class that simply print the message
  13. * with the log level prefix, see derived classes such as TemplatedFormatter
  14. * for more interesting data.
  15. */
  16. class Formatter {
  17. friend class Logger;
  18. static void initialize();
  19. virtual std::string format(EntryContext const& context, std::string const& msg) const;
  20. public:
  21. virtual ~Formatter() {}
  22. std::string operator()(EntryContext const& context, std::string const& msg) {
  23. return format(context, msg);
  24. }
  25. };
  26. typedef std::shared_ptr<Formatter> FormatterPtr;
  27. /**
  28. * Possible fields for FieldStr instance
  29. */
  30. enum class Field {
  31. /// Name of the file (everything following the last path separator)
  32. FileName,
  33. /// Full path of the file
  34. FilePath,
  35. /// Line number
  36. Line,
  37. /// Name of function currently executed
  38. Function,
  39. /// Name of the logger
  40. LoggerName,
  41. /// Message to be logged
  42. Message,
  43. /// Level of the log entry
  44. LogLevel,
  45. /// Number of milliseconds since the logger was initialized
  46. WallTime,
  47. };
  48. /**
  49. * Controls justification of formatted log fields.
  50. */
  51. enum class Justification {
  52. /// Left align field
  53. LEFT,
  54. /// Right align field
  55. RIGHT
  56. };
  57. /**
  58. * Formatter for log entry fields, with the exception of time stamp formatting
  59. * (see TimeStr for that). The Field template argument determines which field
  60. * is printed, see logging::Field.
  61. * The other template arguments control the alignment of the output string.
  62. */
  63. template<Field field, int Width = 0, Justification j = Justification::RIGHT, char Fill = ' '>
  64. class FieldStr {
  65. public:
  66. void stream(std::ostream& os, EntryContext const& context, std::string const& msg) const;
  67. };
  68. /**
  69. * Formatter for log time stamps. The constructor expects a single string
  70. * argument which is a formatter for the time stamp. For the specification of
  71. * this format string see the documentation for std::put_time . You can use for
  72. * example "%c" or "%T".
  73. * The template arguments control the alignment of the output string.
  74. */
  75. class TimeStr {
  76. std::string formatStr;
  77. public:
  78. TimeStr(char const* format) : formatStr(format) {
  79. }
  80. TimeStr(std::string const& format) : formatStr(format) {
  81. }
  82. void stream(std::ostream& os, EntryContext const& context, std::string const&) const;
  83. };
  84. /**
  85. * Formatter which formats the output based on the (templated) arguments given.
  86. * The arguments can be anything that implements the stream operator <<, but
  87. * more interestingly also the various FormatField subclasses. These classes
  88. * can output the various fields associated with a log entry.
  89. */
  90. template<typename ... Formatters>
  91. class TemplateFormatter : public Formatter {
  92. std::tuple<Formatters...> formatters;
  93. template <int N>
  94. typename std::enable_if<N < (sizeof...(Formatters))>::type
  95. formatTuple(EntryContext const& context, std::string const& msg, std::ostream& os) const {
  96. formatElement(std::get<N>(formatters), os, context, msg);
  97. formatTuple<N+1>(context, msg, os);
  98. }
  99. template <int N>
  100. typename std::enable_if<(N >= sizeof...(Formatters))>::type
  101. formatTuple(EntryContext const&, std::string const&, std::ostream&) const {
  102. }
  103. template<Field field, int Width, Justification j, char Fill>
  104. void formatElement(FieldStr<field, Width, j, Fill> const& t, std::ostream& stream, EntryContext const& context, std::string const& msg) const {
  105. t.stream(stream, context, msg);
  106. }
  107. void formatElement(TimeStr const& t, std::ostream& stream, EntryContext const& context, std::string const& msg) const {
  108. t.stream(stream, context, msg);
  109. }
  110. template<typename T>
  111. void formatElement(T const& t, std::ostream& stream, EntryContext const&, std::string const&) const {
  112. stream << t;
  113. }
  114. public:
  115. TemplateFormatter(Formatters ... formatters) :
  116. formatters(std::forward<Formatters>(formatters)...)
  117. {
  118. }
  119. std::string format(EntryContext const& context, std::string const& msg) const override;
  120. };
  121. /**
  122. * Helper function to create a TemplateFormatter. Simply call with some
  123. * formatable arguments, e.g.,
  124. * @code{.cpp}
  125. * logging::makeTemplateFormatter(
  126. * logging::FieldStr<logging::Field::LogLevel>(), " - ",
  127. * logging::FieldStr<logging::Field::Message>(), "\n");
  128. * @endcode
  129. */
  130. template<typename ... Formatters>
  131. FormatterPtr makeTemplateFormatter(Formatters&& ... formatters) {
  132. return std::make_shared<TemplateFormatter<Formatters...>>(std::forward<Formatters>(formatters)...);
  133. }
  134. }