userver: userver/logging/log.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
log.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/logging/log.hpp
4/// @brief Logging helpers
5
6#include <chrono>
7
8#include <userver/compiler/select.hpp>
9#include <userver/logging/fwd.hpp>
10#include <userver/logging/level.hpp>
11#include <userver/logging/log_filepath.hpp>
12#include <userver/logging/log_helper.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace logging {
17
18namespace impl {
19
20void SetDefaultLoggerRef(LoggerRef new_logger) noexcept;
21
22extern bool has_background_threads_which_can_log;
23
24} // namespace impl
25
26/// @brief Returns the default logger previously set by SetDefaultLogger. If the
27/// logger was not set - returns a logger that does no logging.
28///
29/// @note While the coroutine engine is running, any reference to the default
30/// logger is guaranteed to be alive. No lifetime guarantees are given
31/// for the default logger reference outside the engine's lifetime. The rule of
32/// thumb there is not to keep this reference in any extended scope.
33LoggerRef GetDefaultLogger() noexcept;
34
35/// @brief Atomically replaces the default logger.
36///
37/// @warning Do not use this class if you are using a component system.
38class DefaultLoggerGuard final {
39public:
40 /// Atomically replaces the default logger.
41 ///
42 /// @warning The logger should live as long as someone is using it.
43 /// Generally speaking - it should live for a lifetime of the application,
44 /// or for a lifetime of the coroutine engine.
45 explicit DefaultLoggerGuard(LoggerPtr new_default_logger) noexcept;
46
47 DefaultLoggerGuard(DefaultLoggerGuard&&) = delete;
48 DefaultLoggerGuard& operator=(DefaultLoggerGuard&&) = delete;
49
50 ~DefaultLoggerGuard();
51
52private:
53 LoggerRef logger_prev_;
54 const Level level_prev_;
55 LoggerPtr logger_new_;
56};
57
58/// @brief Allows to override global log level for the whole service within a scope. Primarily for use in tests.
59///
60/// @warning This is NOT the right tool to toggle writing of certain logs within a scope.
61/// This scope class changes log level GLOBALLY as-if using @ref logging::SetLoggerLevel.
62///
63/// @note To affect what logs are written within a scope, use @ref tracing::Span::SetLogLevel and
64/// @ref tracing::Span::SetLocalLogLevel (read their docs first!).
65class DefaultLoggerLevelScope final {
66public:
67 explicit DefaultLoggerLevelScope(logging::Level level);
68
69 DefaultLoggerLevelScope(DefaultLoggerLevelScope&&) = delete;
70 DefaultLoggerLevelScope& operator=(DefaultLoggerLevelScope&&) = delete;
71
72 ~DefaultLoggerLevelScope();
73
74private:
75 impl::LoggerBase& logger_;
76 const Level level_initial_;
77};
78
79/// @brief Sets new log level for the default logger
80/// @note Prefer using logging::DefaultLoggerLevelScope if possible
82
83/// Returns log level for the default logger
85
86/// Returns true if the provided log level is greater or equal to
87/// the current log level and to the tracing::Span (if any) local log level.
88bool ShouldLog(Level level) noexcept;
89
90/// Sets new log level for a logger
91void SetLoggerLevel(LoggerRef, Level);
92
93bool LoggerShouldLog(LoggerRef logger, Level level) noexcept;
94
95bool LoggerShouldLog(const LoggerPtr& logger, Level level) noexcept;
96
97Level GetLoggerLevel(LoggerRef logger) noexcept;
98
99/// Forces flush of default logger message queue
100void LogFlush();
101
102/// Forces flush of `logger` message queue
103void LogFlush(LoggerRef logger);
104
105namespace impl {
106
107// Not thread-safe, static lifetime data
108class RateLimitData {
109public:
110 uint64_t count_since_reset = 0;
111 uint64_t dropped_count = 0;
112 std::chrono::steady_clock::time_point last_reset_time{};
113};
114
115// Represents a single rate limit usage
116class RateLimiter {
117public:
118 RateLimiter(RateLimitData& data, Level level) noexcept;
119 bool ShouldLog() const { return should_log_; }
120 void SetShouldNotLog() { should_log_ = false; }
121 Level GetLevel() const { return level_; }
122 friend LogHelper& operator<<(LogHelper& lh, const RateLimiter& rl) noexcept;
123
124private:
125 const Level level_;
126 bool should_log_{true};
127 uint64_t dropped_count_{0};
128};
129
130// Register location during static initialization for dynamic debug logs.
131class StaticLogEntry final {
132public:
133 StaticLogEntry(const char* path, int line) noexcept;
134
135 StaticLogEntry(StaticLogEntry&&) = delete;
136 StaticLogEntry& operator=(StaticLogEntry&&) = delete;
137
138 bool ShouldNotLog(LoggerRef logger, Level level) const noexcept;
139 bool ShouldNotLog(const LoggerPtr& logger, Level level) const noexcept;
140
141private:
142 static constexpr std::size_t kContentSize = compiler::SelectSize().For64Bit(40).For32Bit(24);
143
144 alignas(void*) std::byte content_[kContentSize];
145};
146
147template <class NameHolder, int Line>
148struct EntryStorage final {
149 static inline StaticLogEntry entry{NameHolder::Get(), Line};
150};
151
152} // namespace impl
153
154} // namespace logging
155
156/// @cond
157
158#ifdef USERVER_FEATURE_ERASE_LOG_WITH_LEVEL
159
160// Helper macro to erase the logging related code from binary. Erases the
161// * logging registration via EntryStorage
162// * ShouldLog() calls and related `if` statements and runtime checks
163// * SourceLocation info
164// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
165#define USERVER_IMPL_ERASE_LOG
166 true ? logging::impl::Noop{}
167 : USERVER_NAMESPACE::logging::LogHelper(
168 USERVER_NAMESPACE::logging::GetDefaultLogger(),
169 USERVER_NAMESPACE::logging::Level::kTrace,
170 USERVER_NAMESPACE::utils::impl::SourceLocation::Custom(0, {}, {})
171 )
172 .AsLvalue()
173
174// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
175#define USERVER_IMPL_LOGS_TRACE_ERASER(X) USERVER_IMPL_ERASE_LOG
176
177#if USERVER_FEATURE_ERASE_LOG_WITH_LEVEL > 0
178// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
179#define USERVER_IMPL_LOGS_DEBUG_ERASER(X) USERVER_IMPL_ERASE_LOG
180#endif
181
182#if USERVER_FEATURE_ERASE_LOG_WITH_LEVEL > 1
183// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
184#define USERVER_IMPL_LOGS_INFO_ERASER(X) USERVER_IMPL_ERASE_LOG
185#endif
186
187#if USERVER_FEATURE_ERASE_LOG_WITH_LEVEL > 2
188// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
189#define USERVER_IMPL_LOGS_WARNING_ERASER(X) USERVER_IMPL_ERASE_LOG
190#endif
191
192#if USERVER_FEATURE_ERASE_LOG_WITH_LEVEL > 3
193// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
194#define USERVER_IMPL_LOGS_ERROR_ERASER(X) USERVER_IMPL_ERASE_LOG
195#endif
196
197#endif // #ifdef USERVER_FEATURE_ERASE_LOG_WITH_LEVEL
198
199#ifndef USERVER_IMPL_LOGS_TRACE_ERASER
200// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
201#define USERVER_IMPL_LOGS_TRACE_ERASER(X) X
202#endif
203
204#ifndef USERVER_IMPL_LOGS_DEBUG_ERASER
205// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
206#define USERVER_IMPL_LOGS_DEBUG_ERASER(X) X
207#endif
208
209#ifndef USERVER_IMPL_LOGS_INFO_ERASER
210// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
211#define USERVER_IMPL_LOGS_INFO_ERASER(X) X
212#endif
213
214#ifndef USERVER_IMPL_LOGS_WARNING_ERASER
215// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
216#define USERVER_IMPL_LOGS_WARNING_ERASER(X) X
217#endif
218
219#ifndef USERVER_IMPL_LOGS_ERROR_ERASER
220// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
221#define USERVER_IMPL_LOGS_ERROR_ERASER(X) X
222#endif
223
224// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
225#define USERVER_IMPL_LOG_TO(logger, level, ...)
226 USERVER_NAMESPACE::logging::LogHelper(logger, level, USERVER_NAMESPACE::logging::LogClass::kLog)
227 .AsLvalue(__VA_ARGS__)
228
229// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
230#define USERVER_IMPL_DYNAMIC_DEBUG_ENTRY
231 []() noexcept -> const USERVER_NAMESPACE::logging::impl::StaticLogEntry& {
232 struct NameHolder {
233 static constexpr const char* Get() noexcept { return USERVER_FILEPATH.data(); }
234 };
235 const auto& entry = USERVER_NAMESPACE::logging::impl::EntryStorage<NameHolder, __LINE__>::entry;
236 return entry;
237 }
238 /// @endcond
239
240/// @brief If lvl matches the verbosity then builds a stream and evaluates a
241/// message for the specified logger.
242/// @hideinitializer
243// static_cast<int> below are workarounds for -Wtautological-compare
244// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
245#define LOG_TO(logger, lvl, ...)
246 __builtin_expect(
247 USERVER_IMPL_DYNAMIC_DEBUG_ENTRY().ShouldNotLog((logger), (lvl)),
248 static_cast<int>(lvl) < static_cast<int>(USERVER_NAMESPACE::logging::Level::kInfo)
249 )
250 ? USERVER_NAMESPACE::logging::impl::Noop{}
251 : USERVER_IMPL_LOG_TO((logger), (lvl), __VA_ARGS__)
252
253/// @brief If lvl matches the verbosity then builds a stream and evaluates a
254/// message for the default logger.
255/// @hideinitializer
256// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
257#define LOG(lvl, ...) LOG_TO(USERVER_NAMESPACE::logging::GetDefaultLogger(), (lvl), __VA_ARGS__)
258
259/// @brief Evaluates a message and logs it to the default logger if its level is
260/// below or equal to logging::Level::kTrace
261// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
262#define LOG_TRACE(...) USERVER_IMPL_LOGS_TRACE_ERASER(LOG(USERVER_NAMESPACE::logging::Level::kTrace, __VA_ARGS__))
263
264/// @brief Evaluates a message and logs it to the default logger if its level is
265/// below or equal to logging::Level::kDebug
266// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
267#define LOG_DEBUG(...) USERVER_IMPL_LOGS_DEBUG_ERASER(LOG(USERVER_NAMESPACE::logging::Level::kDebug, __VA_ARGS__))
268
269/// @brief Evaluates a message and logs it to the default logger if its level is
270/// below or equal to logging::Level::kInfo
271// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
272#define LOG_INFO(...) USERVER_IMPL_LOGS_INFO_ERASER(LOG(USERVER_NAMESPACE::logging::Level::kInfo, __VA_ARGS__))
273
274/// @brief Evaluates a message and logs it to the default logger if its level is
275/// below or equal to logging::Level::kWarning
276// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
277#define LOG_WARNING(...) USERVER_IMPL_LOGS_WARNING_ERASER(LOG(USERVER_NAMESPACE::logging::Level::kWarning, __VA_ARGS__))
278
279/// @brief Evaluates a message and logs it to the default logger if its level is
280/// below or equal to logging::Level::kError
281// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
282#define LOG_ERROR(...) USERVER_IMPL_LOGS_ERROR_ERASER(LOG(USERVER_NAMESPACE::logging::Level::kError, __VA_ARGS__))
283
284/// @brief Evaluates a message and logs it to the default logger if its level is
285/// below or equal to logging::Level::kCritical
286// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
287#define LOG_CRITICAL(...) LOG(USERVER_NAMESPACE::logging::Level::kCritical, __VA_ARGS__)
288
289///////////////////////////////////////////////////////////////////////////////
290
291/// @brief Evaluates a message and logs it to the `logger` if its level is below
292/// or equal to logging::Level::kTrace
293// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
294#define LOG_TRACE_TO(logger, ...)
295 USERVER_IMPL_LOGS_TRACE_ERASER(LOG_TO(logger, USERVER_NAMESPACE::logging::Level::kTrace, __VA_ARGS__))
296
297/// @brief Evaluates a message and logs it to the `logger` if its level is below
298/// or equal to logging::Level::kDebug
299// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
300#define LOG_DEBUG_TO(logger, ...)
301 USERVER_IMPL_LOGS_DEBUG_ERASER(LOG_TO(logger, USERVER_NAMESPACE::logging::Level::kDebug, __VA_ARGS__))
302
303/// @brief Evaluates a message and logs it to the `logger` if its level is below
304/// or equal to logging::Level::kInfo
305// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
306#define LOG_INFO_TO(logger, ...)
307 USERVER_IMPL_LOGS_INFO_ERASER(LOG_TO(logger, USERVER_NAMESPACE::logging::Level::kInfo, __VA_ARGS__))
308
309/// @brief Evaluates a message and logs it to the `logger` if its level is below
310/// or equal to logging::Level::kWarning
311// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
312#define LOG_WARNING_TO(logger, ...)
313 USERVER_IMPL_LOGS_WARNING_ERASER(LOG_TO(logger, USERVER_NAMESPACE::logging::Level::kWarning, __VA_ARGS__))
314
315/// @brief Evaluates a message and logs it to the `logger` if its level is below
316/// or equal to logging::Level::kError
317// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
318#define LOG_ERROR_TO(logger, ...)
319 USERVER_IMPL_LOGS_ERROR_ERASER(LOG_TO(logger, USERVER_NAMESPACE::logging::Level::kError, __VA_ARGS__))
320
321/// @brief Evaluates a message and logs it to the `logger` if its level is below
322/// or equal to logging::Level::kCritical
323// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
324#define LOG_CRITICAL_TO(logger, ...) LOG_TO(logger, USERVER_NAMESPACE::logging::Level::kCritical, __VA_ARGS__)
325
326///////////////////////////////////////////////////////////////////////////////
327
328/// @brief If lvl matches the verbosity then builds a stream and evaluates a
329/// message for the logger. Ignores log messages that occur too often.
330/// @hideinitializer
331// Note: we have to jump through the hoops to keep lazy evaluation of the logged
332// data AND log the dropped logs count from the correct LogHelper in the face of
333// multithreading and coroutines.
334// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
335#define LOG_LIMITED_TO(logger, lvl, ...)
336 for (USERVER_NAMESPACE::logging::impl::RateLimiter log_limited_to_rl{
337 []() -> USERVER_NAMESPACE::logging::impl::RateLimitData& {
338 thread_local USERVER_NAMESPACE::logging::impl::RateLimitData rl_data;
339 return rl_data;
340 }(),
341 (lvl)};
342 log_limited_to_rl.ShouldLog();
343 log_limited_to_rl.SetShouldNotLog())
344 LOG_TO((logger), log_limited_to_rl.GetLevel(), __VA_ARGS__) << log_limited_to_rl
345
346/// @brief If lvl matches the verbosity then builds a stream and evaluates a
347/// message for the default logger. Ignores log messages that occur too often.
348// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
349#define LOG_LIMITED(lvl, ...) LOG_LIMITED_TO(USERVER_NAMESPACE::logging::GetDefaultLogger(), (lvl), __VA_ARGS__)
350
351/// @brief Evaluates a message and logs it to the default logger if the log
352/// message does not occur too often and default logger level is below or equal
353/// to logging::Level::kTrace.
354// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
355#define LOG_LIMITED_TRACE(...)
356 USERVER_IMPL_LOGS_TRACE_ERASER(LOG_LIMITED(USERVER_NAMESPACE::logging::Level::kTrace, __VA_ARGS__))
357
358/// @brief Evaluates a message and logs it to the default logger if the log
359/// message does not occur too often and default logger level is below or equal
360/// to logging::Level::kDebug.
361// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
362#define LOG_LIMITED_DEBUG(...)
363 USERVER_IMPL_LOGS_DEBUG_ERASER(LOG_LIMITED(USERVER_NAMESPACE::logging::Level::kDebug, __VA_ARGS__))
364
365/// @brief Evaluates a message and logs it to the default logger if the log
366/// message does not occur too often and default logger level is below or equal
367/// to logging::Level::kInfo.
368// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
369#define LOG_LIMITED_INFO(...)
370 USERVER_IMPL_LOGS_INFO_ERASER(LOG_LIMITED(USERVER_NAMESPACE::logging::Level::kInfo, __VA_ARGS__))
371
372/// @brief Evaluates a message and logs it to the default logger if the log
373/// message does not occur too often and default logger level is below or equal
374/// to logging::Level::kWarning.
375// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
376#define LOG_LIMITED_WARNING(...)
377 USERVER_IMPL_LOGS_WARNING_ERASER(LOG_LIMITED(USERVER_NAMESPACE::logging::Level::kWarning, __VA_ARGS__))
378
379/// @brief Evaluates a message and logs it to the default logger if the log
380/// message does not occur too often and default logger level is below or equal
381/// to logging::Level::kError.
382// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
383#define LOG_LIMITED_ERROR(...)
384 USERVER_IMPL_LOGS_ERROR_ERASER(LOG_LIMITED(USERVER_NAMESPACE::logging::Level::kError, __VA_ARGS__))
385
386/// @brief Evaluates a message and logs it to the default logger if the log
387/// message does not occur too often and default logger level is below or equal
388/// to logging::Level::kCritical.
389// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
390#define LOG_LIMITED_CRITICAL(...) LOG_LIMITED(USERVER_NAMESPACE::logging::Level::kCritical, __VA_ARGS__)
391
392///////////////////////////////////////////////////////////////////////////////
393
394/// @brief Evaluates a message and logs it to the `logger` if the log message
395/// does not occur too often and `logger` level is below or equal to
396/// logging::Level::kTrace.
397// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
398#define LOG_LIMITED_TRACE_TO(logger, ...)
399 USERVER_IMPL_LOGS_TRACE_ERASER(LOG_LIMITED_TO(logger, USERVER_NAMESPACE::logging::Level::kTrace, __VA_ARGS__))
400
401/// @brief Evaluates a message and logs it to the `logger` if the log message
402/// does not occur too often and `logger` level is below or equal to
403/// logging::Level::kDebug.
404// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
405#define LOG_LIMITED_DEBUG_TO(logger, ...)
406 USERVER_IMPL_LOGS_DEBUG_ERASER(LOG_LIMITED_TO(logger, USERVER_NAMESPACE::logging::Level::kDebug, __VA_ARGS__))
407
408/// @brief Evaluates a message and logs it to the `logger` if the log message
409/// does not occur too often and `logger` level is below or equal to
410/// logging::Level::kInfo.
411// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
412#define LOG_LIMITED_INFO_TO(logger, ...)
413 USERVER_IMPL_LOGS_INFO_ERASER(LOG_LIMITED_TO(logger, USERVER_NAMESPACE::logging::Level::kInfo, __VA_ARGS__))
414
415/// @brief Evaluates a message and logs it to the `logger` if the log message
416/// does not occur too often and `logger` level is below or equal to
417/// logging::Level::kWarning.
418// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
419#define LOG_LIMITED_WARNING_TO(logger, ...)
420 USERVER_IMPL_LOGS_WARNING_ERASER(LOG_LIMITED_TO(logger, USERVER_NAMESPACE::logging::Level::kWarning, __VA_ARGS__))
421
422/// @brief Evaluates a message and logs it to the `logger` if the log message
423/// does not occur too often and `logger` level is below or equal to
424/// logging::Level::kError.
425// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
426#define LOG_LIMITED_ERROR_TO(logger, ...)
427 USERVER_IMPL_LOGS_ERROR_ERASER(LOG_LIMITED_TO(logger, USERVER_NAMESPACE::logging::Level::kError, __VA_ARGS__))
428
429/// @brief Evaluates a message and logs it to the `logger` if the log message
430/// does not occur too often and `logger` level is below or equal to
431/// logging::Level::kCritical.
432// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
433#define LOG_LIMITED_CRITICAL_TO(logger, ...)
434 LOG_LIMITED_TO(logger, USERVER_NAMESPACE::logging::Level::kCritical, __VA_ARGS__)
435
436USERVER_NAMESPACE_END