quill
MacroMetadata.h
1 
7 #pragma once
8 
9 #include "quill/core/Attributes.h"
10 #include "quill/core/Common.h"
11 #include "quill/core/LogLevel.h"
12 
13 #include <cstddef>
14 #include <cstdint>
15 #include <string_view>
16 
17 QUILL_BEGIN_NAMESPACE
18 
19 QUILL_BEGIN_EXPORT
20 
25 {
26 public:
27  enum Event : uint8_t
28  {
29  None,
30  Log,
31  InitBacktrace,
32  FlushBacktrace,
33  Flush,
34  LogWithRuntimeMetadataDeepCopy,
35  LogWithRuntimeMetadataHybridCopy,
36  LogWithRuntimeMetadataShallowCopy,
37  LoggerRemovalRequest,
38  Metric,
39  MdcSet,
40  MdcErase,
41  MdcClear
42  };
43 
44  constexpr MacroMetadata() = default;
45 
46  constexpr MacroMetadata(char const* source_location, char const* caller_function,
47  char const* message_format, char const* tags, LogLevel log_level, Event event) noexcept
48  : _source_location(source_location),
49  _caller_function(caller_function),
50  _message_format(message_format),
51  _tags(tags),
52  _colon_separator_pos(_calc_colon_separator_pos()),
53  _file_name_pos(_calc_file_name_pos()),
54  _log_level(log_level),
55  _event(event)
56  {
57  }
58 
59  QUILL_NODISCARD char const* source_location() const noexcept { return _source_location; }
60 
61  QUILL_NODISCARD char const* caller_function() const noexcept { return _caller_function; }
62 
63  QUILL_NODISCARD char const* message_format() const noexcept { return _message_format; }
64 
65  QUILL_NODISCARD char const* line() const noexcept
66  {
67  if (QUILL_UNLIKELY(_source_location[_colon_separator_pos] == '\0'))
68  {
69  return _source_location + _colon_separator_pos;
70  }
71 
72  return _source_location + _colon_separator_pos + 1;
73  }
74 
75  QUILL_NODISCARD std::string_view full_path() const noexcept
76  {
77  return std::string_view{_source_location, _colon_separator_pos};
78  }
79 
80  QUILL_NODISCARD std::string_view file_name() const noexcept
81  {
82  return std::string_view{_source_location + _file_name_pos,
83  static_cast<size_t>(_colon_separator_pos - _file_name_pos)};
84  }
85 
86  QUILL_NODISCARD char const* short_source_location() const noexcept
87  {
88  return _source_location + _file_name_pos;
89  }
90 
91  QUILL_NODISCARD LogLevel log_level() const noexcept { return _log_level; }
92 
93  QUILL_NODISCARD char const* tags() const noexcept { return _tags; }
94 
95  QUILL_NODISCARD constexpr bool has_named_args() const noexcept
96  {
97  return contains_named_args(_message_format);
98  }
99 
100  QUILL_NODISCARD Event event() const noexcept { return _event; }
101 
102  /***/
103  QUILL_NODISCARD static constexpr bool contains_named_args(std::string_view fmt) noexcept
104  {
105  uint32_t pos{0};
106  bool found_named_arg{false};
107 
108  // Iterates the format string and checks if any characters are contained inside `{}`
109  while (pos < fmt.length())
110  {
111  if (fmt[pos] == '{')
112  {
113  ++pos; // consume {
114  if (pos >= fmt.length())
115  {
116  break;
117  }
118 
119  // first character after the {
120  auto const fc = fmt[pos];
121  if (fc == '{')
122  {
123  // this means first '{' was escaped, so we ignore both of them
124  ++pos;
125  continue;
126  }
127 
128  // else look for the next '}'
129  uint32_t char_cnt{0};
130  while (pos < fmt.length())
131  {
132  if (fmt[pos] == '}')
133  {
134  ++pos; // consume }
135  if (pos >= fmt.length())
136  {
137  break;
138  }
139 
140  if (fmt[pos] == '}')
141  {
142  // this means first '}', was escaped ignore it
143  ++pos;
144  ++char_cnt;
145  continue;
146  }
147 
148  // we found '{' match, we can break
149  break;
150  }
151 
152  ++pos;
153  ++char_cnt;
154  }
155 
156  if ((char_cnt != 0) && ((fc >= 'a' && fc <= 'z') || (fc >= 'A' && fc <= 'Z') || (fc == '_')))
157  {
158  found_named_arg = true;
159  }
160  continue;
161  }
162  ++pos;
163  }
164 
165  return found_named_arg;
166  }
167 
168 private:
169  /***/
170  QUILL_NODISCARD constexpr uint16_t _calc_file_name_pos() const noexcept
171  {
172  char const* source_location = _source_location;
173  char const* file = source_location;
174  while (*source_location)
175  {
176  char cur = *source_location++;
177  if (cur == '/' || cur == detail::PATH_PREFERRED_SEPARATOR)
178  {
179  file = source_location;
180  }
181  }
182  return static_cast<uint16_t>(file - _source_location);
183  }
184 
185  /***/
186  QUILL_NODISCARD constexpr uint16_t _calc_colon_separator_pos() const noexcept
187  {
188  // std::string_view::rfind is only constexpr from C++20
189  size_t length = 0;
190  while (_source_location[length] != '\0')
191  {
192  ++length;
193  }
194 
195  for (size_t i = length; i > 0; --i)
196  {
197  if (_source_location[i - 1] == ':')
198  {
199  return static_cast<uint16_t>(i - 1);
200  }
201  }
202 
203  return static_cast<uint16_t>(length);
204  }
205 
206 private:
207  char const* _source_location{nullptr};
208  char const* _caller_function{nullptr};
209  char const* _message_format{nullptr};
210  char const* _tags{nullptr};
211  uint16_t _colon_separator_pos{0};
212  uint16_t _file_name_pos{0};
213  LogLevel _log_level{LogLevel::None};
214  Event _event{Event::None};
215 };
216 
217 QUILL_END_EXPORT
218 
219 static_assert(sizeof(MacroMetadata) <= detail::QUILL_CACHE_LINE_SIZE,
220  "Size of MacroMetadata exceeds the cache line size");
221 
222 QUILL_END_NAMESPACE
Captures and stores information about a logging event in compile time.
Definition: MacroMetadata.h:24
constexpr size_t QUILL_CACHE_LINE_SIZE
Cache line constants.
Definition: Common.h:67