quill
TransitEvent.h
1 
7 #pragma once
8 
9 #include "quill/core/Attributes.h"
10 #include "quill/core/Codec.h"
11 #include "quill/core/LogLevel.h"
12 #include "quill/core/MacroMetadata.h"
13 
14 #include "quill/bundled/fmt/format.h"
15 
16 #include <atomic>
17 #include <cstdint>
18 #include <memory>
19 #include <string>
20 #include <string_view>
21 #include <utility>
22 #include <variant>
23 #include <vector>
24 
25 QUILL_BEGIN_NAMESPACE
26 
27 namespace detail
28 {
30 class LoggerBase;
31 
32 /***/
34 {
35  using FormatBuffer = fmtquill::basic_memory_buffer<char, 88>;
36 
37  /***/
38  TransitEvent() = default;
39 
40  /***/
41  ~TransitEvent() = default;
42 
46  TransitEvent(TransitEvent const& other) = delete;
47  TransitEvent& operator=(TransitEvent const& other) = delete;
48 
49  /***/
50  TransitEvent(TransitEvent&& other) noexcept
51  : timestamp(other.timestamp),
52  macro_metadata(other.macro_metadata),
53  logger_base(other.logger_base),
54  formatted_msg(std::move(other.formatted_msg)),
55  extra_data(std::move(other.extra_data)),
56  event_payload(std::move(other.event_payload))
57  {
58  other.event_payload = std::monostate{};
59 
60  // Update macro_metadata pointer if it was pointing to runtime_metadata
61  if (extra_data && extra_data->runtime_metadata.has_runtime_metadata)
62  {
63  // Point to our own runtime_metadata instead of the moved-from object's
64  macro_metadata = &extra_data->runtime_metadata.macro_metadata;
65  }
66  }
67 
68  /***/
69  TransitEvent& operator=(TransitEvent&& other) noexcept
70  {
71  if (this != &other)
72  {
73  timestamp = other.timestamp;
74  macro_metadata = other.macro_metadata;
75  logger_base = other.logger_base;
76  formatted_msg = std::move(other.formatted_msg);
77  extra_data = std::move(other.extra_data);
78  event_payload = std::move(other.event_payload);
79  other.event_payload = std::monostate{};
80 
81  if (extra_data && extra_data->runtime_metadata.has_runtime_metadata)
82  {
83  // Point to our own runtime_metadata instead of the moved-from object's
84  macro_metadata = &extra_data->runtime_metadata.macro_metadata;
85  }
86  }
87 
88  return *this;
89  }
90 
91  /***/
92  void copy_to(TransitEvent& other) const
93  {
94  other.timestamp = timestamp;
95  other.macro_metadata = macro_metadata;
96  other.logger_base = logger_base;
98 
99  // manually copy the fmt::buffer
100  other.formatted_msg->clear();
101  other.formatted_msg->reserve(formatted_msg->size());
102  other.formatted_msg->append(*formatted_msg);
103 
104  if (extra_data)
105  {
106  other.extra_data = std::make_unique<ExtraData>(*extra_data);
107 
108  if (other.extra_data->runtime_metadata.has_runtime_metadata)
109  {
110  // then point macro_metadata to the correct object
111  other.macro_metadata = &other.extra_data->runtime_metadata.macro_metadata;
112  }
113  }
114  }
115 
116  /***/
117  QUILL_NODISCARD QUILL_ATTRIBUTE_HOT LogLevel log_level() const noexcept
118  {
119  return macro_metadata->log_level();
120  }
121 
122  /***/
123  QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::vector<std::pair<std::string, std::string>>* get_named_args() const noexcept
124  {
125  // TransitEvents are pooled, so `extra_data` may have been allocated by a previous log on
126  // this slot
127  if (!extra_data || !macro_metadata || !macro_metadata->has_named_args())
128  {
129  return nullptr;
130  }
131 
132  return &extra_data->named_args;
133  }
134 
135  /***/
136  QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::string_view mdc() const noexcept
137  {
138  return extra_data ? extra_data->mdc : std::string_view{};
139  }
140 
141  /***/
142  QUILL_ATTRIBUTE_HOT void ensure_extra_data()
143  {
144  if (extra_data)
145  {
146  return;
147  }
148 
149  extra_data = std::make_unique<ExtraData>();
150  }
151 
152  QUILL_ATTRIBUTE_HOT void set_flush_flag(std::atomic<bool>* flush_flag_ptr) noexcept
153  {
154  event_payload = flush_flag_ptr;
155  }
156 
157  QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::atomic<bool>* flush_flag() const noexcept
158  {
159  QUILL_ASSERT(std::holds_alternative<std::atomic<bool>*>(event_payload),
160  "Attempted to read a flush flag from a TransitEvent with a non-flush payload");
161  std::atomic<bool>* const flush_flag_ptr = std::get<std::atomic<bool>*>(event_payload);
162  QUILL_ASSERT(flush_flag_ptr != nullptr,
163  "Attempted to read a null flush flag from a TransitEvent");
164  return flush_flag_ptr;
165  }
166 
167  QUILL_ATTRIBUTE_HOT void set_metric_value(double value) noexcept { event_payload = value; }
168 
169  QUILL_ATTRIBUTE_HOT void reset_payload() noexcept { event_payload = std::monostate{}; }
170 
171  QUILL_NODISCARD QUILL_ATTRIBUTE_HOT bool has_metric_value() const noexcept
172  {
173  return std::holds_alternative<double>(event_payload);
174  }
175 
176  QUILL_NODISCARD QUILL_ATTRIBUTE_HOT double metric_value() const noexcept
177  {
178  QUILL_ASSERT(has_metric_value(),
179  "Attempted to read a metric value from a TransitEvent without one");
180  return std::get<double>(event_payload);
181  }
182 
184  {
185  RuntimeMetadata() = default;
186 
187  RuntimeMetadata(char const* file, uint32_t line, char const* function, char const* in_tags,
188  char const* in_fmt, LogLevel log_level)
189  : fmt(_safe_string(in_fmt)),
190  source_location(_format_file_location(file, line)),
191  function_name(_safe_string(function)),
192  tags(_safe_string(in_tags)),
193  macro_metadata(source_location.data(), function_name.data(), fmt.data(),
194  tags.empty() ? nullptr : tags.data(), log_level, MacroMetadata::Event::Log),
195  has_runtime_metadata(true)
196  {
197  }
198 
199  RuntimeMetadata(RuntimeMetadata const& other)
200  : fmt(other.fmt),
201  source_location(other.source_location),
202  function_name(other.function_name),
203  tags(other.tags),
204  macro_metadata(source_location.data(), function_name.data(), fmt.data(),
205  tags.empty() ? nullptr : tags.data(), other.macro_metadata.log_level(),
206  MacroMetadata::Event::Log),
207  has_runtime_metadata(other.has_runtime_metadata)
208  {
209  // Recreate macro_metadata to point to our own strings
210  }
211 
212  RuntimeMetadata& operator=(RuntimeMetadata const& other)
213  {
214  if (this != &other)
215  {
216  fmt = other.fmt;
217  source_location = other.source_location;
218  function_name = other.function_name;
219  tags = other.tags;
220  has_runtime_metadata = other.has_runtime_metadata;
221 
222  // Recreate macro_metadata to point to our own strings
223  macro_metadata = MacroMetadata(source_location.data(), function_name.data(), fmt.data(),
224  tags.empty() ? nullptr : tags.data(),
225  other.macro_metadata.log_level(), MacroMetadata::Event::Log);
226  }
227  return *this;
228  }
229 
230  RuntimeMetadata(RuntimeMetadata&& other) noexcept = delete;
231  RuntimeMetadata& operator=(RuntimeMetadata&& other) noexcept = delete;
232 
233  std::string fmt;
234  std::string source_location;
235  std::string function_name;
236  std::string tags;
237  MacroMetadata macro_metadata;
238  bool has_runtime_metadata{false};
239 
240  private:
241  QUILL_NODISCARD static char const* _safe_string(char const* value) noexcept
242  {
243  return value ? value : "";
244  }
245 
246  QUILL_NODISCARD static std::string _format_file_location(char const* file, uint32_t line)
247  {
248  if (!file || (file[0] == '\0' && line == 0))
249  {
250  return std::string{};
251  }
252 
253  // Format as "file:line"
254  return std::string{file} + ":" + std::to_string(line);
255  }
256  };
257 
258  struct ExtraData
259  {
260  // Additional fields that are used for some features as a separate structure to keep
261  // TransitEvent size smaller for the main scenarios
262  std::vector<std::pair<std::string, std::string>> named_args;
263  std::string mdc;
264  RuntimeMetadata runtime_metadata;
265  };
266 
267  uint64_t timestamp{0};
268  MacroMetadata const* macro_metadata{nullptr};
269  LoggerBase* logger_base{nullptr};
270  std::unique_ptr<FormatBuffer> formatted_msg{std::make_unique<FormatBuffer>()};
271  std::unique_ptr<ExtraData> extra_data;
272  std::variant<std::monostate, std::atomic<bool>*, double> event_payload{
273  std::monostate{}};
274 };
275 } // namespace detail
276 
277 QUILL_END_NAMESPACE
std::unique_ptr< ExtraData > extra_data
buffer for message
Definition: TransitEvent.h:271
Definition: TransitEvent.h:33
Definition: TransitEvent.h:183
Captures and stores information about a logging event in compile time.
Definition: MacroMetadata.h:24
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:28
Definition: TransitEvent.h:258
Definition: base.h:2200
Definition: LoggerBase.h:39
std::variant< std::monostate, std::atomic< bool > *, double > event_payload
A unique ptr to save space as these fields not always used.
Definition: TransitEvent.h:272