9 #include "quill/UserClockSource.h" 10 #include "quill/core/Attributes.h" 11 #include "quill/core/ChronoTimeUtils.h" 12 #include "quill/core/Codec.h" 13 #include "quill/core/Common.h" 14 #include "quill/core/FrontendOptions.h" 15 #include "quill/core/LogLevel.h" 16 #include "quill/core/LoggerBase.h" 17 #include "quill/core/MacroMetadata.h" 18 #include "quill/core/Rdtsc.h" 47 template <
typename TFrontendOptions>
51 using frontend_options_t = TFrontendOptions;
53 static constexpr
bool using_unbounded_queue =
54 (frontend_options_t::queue_type == QueueType::UnboundedBlocking) ||
55 (frontend_options_t::queue_type == QueueType::UnboundedDropping);
74 template <
bool enable_immediate_flush,
typename... Args>
78 assert((macro_metadata->event() != MacroMetadata::Event::LogWithRuntimeMetadataDeepCopy &&
79 macro_metadata->event() != MacroMetadata::Event::LogWithRuntimeMetadataShallowCopy &&
80 macro_metadata->event() != MacroMetadata::Event::LogWithRuntimeMetadataHybridCopy) &&
81 "Should not be called with MacroMetadata::Event::LogWithRuntimeMetadata");
83 assert(_valid.load(std::memory_order_acquire) &&
"Invalidated loggers can not log");
88 uint64_t
const current_timestamp = _get_message_timestamp();
90 if (QUILL_UNLIKELY(_thread_context ==
nullptr))
93 _thread_context = detail::get_local_thread_context<frontend_options_t>();
97 size_t total_size =
sizeof(current_timestamp) + (
sizeof(uintptr_t) * 3) +
99 _thread_context->get_conditional_arg_size_cache(), fmt_args...);
101 std::byte* write_buffer = _reserve_queue_space(total_size, macro_metadata);
103 if (QUILL_UNLIKELY(write_buffer ==
nullptr))
111 std::byte
const*
const write_begin = write_buffer;
116 write_buffer = _encode_header(write_buffer, current_timestamp, macro_metadata,
this,
117 detail::decode_and_store_args<detail::remove_cvref_t<Args>...>);
120 detail::encode(write_buffer, _thread_context->get_conditional_arg_size_cache(), fmt_args...);
123 assert((write_buffer > write_begin) &&
"write_buffer must be greater than write_begin");
124 assert(total_size == (static_cast<size_t>(write_buffer - write_begin)) &&
125 "The committed write bytes must be equal to the total_size requested bytes");
128 _commit_log_statement<enable_immediate_flush>(total_size);
150 template <
bool enable_immediate_flush,
typename... Args>
152 char const* fmt,
char const* file_path,
153 char const* function_name,
154 char const* tags, uint32_t line_number,
155 LogLevel log_level, Args&&... fmt_args)
158 assert((macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataDeepCopy ||
159 macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataHybridCopy ||
160 macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataShallowCopy) &&
161 "Should only be called with MacroMetadata::Event::LogWithRuntimeMetadata");
163 assert(_valid.load(std::memory_order_acquire) &&
"Invalidated loggers can not log");
168 uint64_t
const current_timestamp = _get_message_timestamp();
170 if (QUILL_UNLIKELY(_thread_context ==
nullptr))
173 _thread_context = detail::get_local_thread_context<frontend_options_t>();
178 size_t total_size{
sizeof(current_timestamp) + (
sizeof(uintptr_t) * 3)};
180 if (macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataDeepCopy)
183 _thread_context->get_conditional_arg_size_cache(), fmt, file_path, function_name, tags,
184 line_number, log_level, fmt_args...);
186 else if (macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataShallowCopy)
189 _thread_context->get_conditional_arg_size_cache(),
static_cast<void const*
>(fmt),
190 static_cast<void const*>(file_path),
static_cast<void const*
>(function_name),
191 static_cast<void const*>(tags), line_number, log_level, fmt_args...);
193 else if (macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataHybridCopy)
196 _thread_context->get_conditional_arg_size_cache(), fmt,
static_cast<void const*
>(file_path),
197 static_cast<void const*>(function_name), tags, line_number, log_level, fmt_args...);
204 std::byte* write_buffer = _reserve_queue_space(total_size, macro_metadata);
206 if (QUILL_UNLIKELY(write_buffer ==
nullptr))
214 std::byte
const*
const write_begin = write_buffer;
219 write_buffer = _encode_header(write_buffer, current_timestamp, macro_metadata,
this,
220 detail::decode_and_store_args<detail::remove_cvref_t<Args>...>);
222 if (macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataDeepCopy)
225 detail::encode(write_buffer, _thread_context->get_conditional_arg_size_cache(), fmt,
226 file_path, function_name, tags, line_number, log_level, fmt_args...);
228 else if (macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataShallowCopy)
230 detail::encode(write_buffer, _thread_context->get_conditional_arg_size_cache(),
231 static_cast<void const*
>(fmt), static_cast<void const*>(file_path),
232 static_cast<void const*
>(function_name), static_cast<void const*>(tags),
233 line_number, log_level, fmt_args...);
235 else if (macro_metadata->event() == MacroMetadata::Event::LogWithRuntimeMetadataHybridCopy)
237 detail::encode(write_buffer, _thread_context->get_conditional_arg_size_cache(), fmt,
238 static_cast<void const*
>(file_path), static_cast<void const*>(function_name),
239 tags, line_number, log_level, fmt_args...);
243 assert((write_buffer > write_begin) &&
"write_buffer must be greater than write_begin");
244 assert(total_size == (static_cast<size_t>(write_buffer - write_begin)) &&
245 "The committed write bytes must be equal to the total_size requested bytes");
248 _commit_log_statement<enable_immediate_flush>(total_size);
260 void init_backtrace(uint32_t max_capacity, LogLevel flush_level = LogLevel::None)
264 "",
"",
"{}",
nullptr, LogLevel::Critical, MacroMetadata::Event::InitBacktrace};
268 while (!this->
template log_statement<false>(¯o_metadata, max_capacity))
270 std::this_thread::sleep_for(std::chrono::nanoseconds{100});
274 _backtrace_flush_level.store(flush_level, std::memory_order_relaxed);
284 "",
"",
"",
nullptr, LogLevel::Critical, MacroMetadata::Event::FlushBacktrace};
287 while (!this->
template log_statement<false>(¯o_metadata))
289 std::this_thread::sleep_for(std::chrono::nanoseconds{100});
313 "",
"",
"",
nullptr, LogLevel::Critical, MacroMetadata::Event::Flush};
315 std::atomic<bool> backend_thread_flushed{
false};
316 std::atomic<bool>* backend_thread_flushed_ptr = &backend_thread_flushed;
319 while (!this->log_statement<false>(¯o_metadata, reinterpret_cast<uintptr_t>(backend_thread_flushed_ptr)))
321 if (sleep_duration_ns > 0)
323 std::this_thread::sleep_for(std::chrono::nanoseconds{sleep_duration_ns});
327 std::this_thread::yield();
332 while (!backend_thread_flushed.load())
334 if (sleep_duration_ns > 0)
336 std::this_thread::sleep_for(std::chrono::nanoseconds{sleep_duration_ns});
340 std::this_thread::yield();
350 LoggerImpl(std::string logger_name, std::vector<std::shared_ptr<Sink>> sinks,
354 static_cast<std::string&&>(logger_name),
static_cast<std::vector<std::shared_ptr<Sink>
>&&>(sinks),
355 static_cast<PatternFormatterOptions&&>(pattern_formatter_options), clock_source, user_clock)
358 if (this->_user_clock)
361 this->_clock_source = ClockSourceType::User;
369 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT uint64_t _get_message_timestamp()
const 374 if (_clock_source == ClockSourceType::Tsc)
379 if (_clock_source == ClockSourceType::System)
381 return detail::get_timestamp_ns<std::chrono::system_clock>();
386 return _user_clock->now();
399 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::byte* _reserve_queue_space(
size_t total_size,
402 std::byte* write_buffer =
403 _thread_context->get_spsc_queue<frontend_options_t::queue_type>().prepare_write(total_size);
405 if constexpr ((frontend_options_t::queue_type == QueueType::BoundedDropping) ||
406 (frontend_options_t::queue_type == QueueType::UnboundedDropping))
408 if (QUILL_UNLIKELY(write_buffer ==
nullptr))
411 if (macro_metadata->event() == MacroMetadata::Event::Log)
413 _thread_context->increment_failure_counter();
417 else if constexpr ((frontend_options_t::queue_type == QueueType::BoundedBlocking) ||
418 (frontend_options_t::queue_type == QueueType::UnboundedBlocking))
420 if (QUILL_UNLIKELY(write_buffer ==
nullptr))
422 if (macro_metadata->event() == MacroMetadata::Event::Log)
424 _thread_context->increment_failure_counter();
429 if constexpr (frontend_options_t::blocking_queue_retry_interval_ns > 0)
431 std::this_thread::sleep_for(std::chrono::nanoseconds{frontend_options_t::blocking_queue_retry_interval_ns});
436 _thread_context->get_spsc_queue<frontend_options_t::queue_type>().prepare_write(total_size);
437 }
while (write_buffer ==
nullptr);
448 template <
bool enable_immediate_flush>
449 QUILL_ATTRIBUTE_HOT
void _commit_log_statement(
size_t total_size)
451 _thread_context->get_spsc_queue<frontend_options_t::queue_type>().finish_and_commit_write(total_size);
453 if constexpr (enable_immediate_flush)
455 uint32_t
const threshold = _message_flush_threshold.load(std::memory_order_relaxed);
456 if (QUILL_UNLIKELY(threshold != 0))
458 uint32_t
const prev = _messages_since_last_flush.fetch_add(1, std::memory_order_relaxed);
459 if ((prev + 1) >= threshold)
461 _messages_since_last_flush.store(0, std::memory_order_relaxed);
476 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT
static std::byte* _encode_header(std::byte* write_buffer, uint64_t timestamp,
481 std::memcpy(write_buffer, ×tamp,
sizeof(timestamp));
482 write_buffer +=
sizeof(timestamp);
484 std::memcpy(write_buffer, &metadata,
sizeof(uintptr_t));
485 write_buffer +=
sizeof(uintptr_t);
487 std::memcpy(write_buffer, &logger_ctx,
sizeof(uintptr_t));
488 write_buffer +=
sizeof(uintptr_t);
490 std::memcpy(write_buffer, &decoder,
sizeof(uintptr_t));
491 write_buffer +=
sizeof(uintptr_t);
void init_backtrace(uint32_t max_capacity, LogLevel flush_level=LogLevel::None)
Init a backtrace for this logger.
Definition: Logger.h:260
Base class for sinks.
Definition: Sink.h:40
void(*)(std::byte *&data, DynamicFormatArgStore &args_store) FormatArgsDecoder
Decode functions.
Definition: Codec.h:382
QUILL_NODISCARD QUILL_ATTRIBUTE_HOT size_t compute_encoded_size_and_cache_string_lengths(QUILL_MAYBE_UNUSED SizeCacheVector &conditional_arg_size_cache, Args const &... args)
Calculates the total size required to encode the provided arguments.
Definition: Codec.h:337
void flush_backtrace()
Dump any stored backtrace messages.
Definition: Logger.h:280
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
QUILL_ATTRIBUTE_HOT bool log_statement(MacroMetadata const *macro_metadata, Args &&... fmt_args)
Push a log message to the spsc queue to be logged by the backend thread.
Definition: Logger.h:75
Thread safe logger.
Definition: Logger.h:48
QUILL_ATTRIBUTE_HOT bool log_statement_runtime_metadata(MacroMetadata const *macro_metadata, char const *fmt, char const *file_path, char const *function_name, char const *tags, uint32_t line_number, LogLevel log_level, Args &&... fmt_args)
Push a log message with runtime metadata to the spsc queue to be logged by the backend thread...
Definition: Logger.h:151
QUILL_NODISCARD QUILL_ATTRIBUTE_HOT uint64_t rdtsc() noexcept
Get the TSC counter.
Definition: Rdtsc.h:109
QUILL_ATTRIBUTE_HOT void encode(std::byte *&buffer, SizeCacheVector const &conditional_arg_size_cache, Args const &... args)
Encodes multiple arguments into a buffer.
Definition: Codec.h:365
Definition: LoggerBase.h:36
Base class that provides a timestamp for log statements based on a user-provided clock source...
Definition: UserClockSource.h:25
void flush_log(uint32_t sleep_duration_ns=100)
Blocks the calling thread until all log messages up to the current timestamp are flushed.
Definition: Logger.h:310
Definition: BackendWorker.h:72
Definition: LoggerManager.h:34