VLink  2.0.0
A high-performance communication middleware
logger.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file logger.h
26  * @brief Singleton logger with stream / format / printf / RAII-stream entry points.
27  *
28  * @details
29  * @c vlink::Logger is the central logging facility. A single instance is constructed via
30  * @c Logger::init and reused for the rest of the process; each call routes through a console
31  * sink and an optional file sink whose minimum levels are independently configurable.
32  *
33  * @par Entry point cheat sheet
34  *
35  * | Style | Macro family | Backing API | Argument shape |
36  * | --------------- | --------------- | ----------------------------- | ------------------------------- |
37  * | Stream | @c VLOG_x | @c FastStream operator<< | @c VLOG_I("x=", x, " y=", y) |
38  * | Placeholder | @c MLOG_x | @c vlink::format::format_to_n | @c MLOG_W("x={} y={}", x, y) |
39  * | printf | @c CLOG_x | @c std::snprintf | @c CLOG_E("errno=%d", err) |
40  * | RAII stream | @c SLOG_x | @c WrapperStream | @c SLOG_D @c << "a=" @c << a |
41  *
42  * @par Severity ladder
43  *
44  * | Value | Name | Use case |
45  * | ----- | --------- | ----------------------------------------- |
46  * | 0 | @c kTrace | Verbose internals |
47  * | 1 | @c kDebug | Developer diagnostics |
48  * | 2 | @c kInfo | Normal operational messages |
49  * | 3 | @c kWarn | Unusual but recoverable conditions |
50  * | 4 | @c kError | Errors that may affect operation |
51  * | 5 | @c kFatal | Unrecoverable; throws @c RuntimeError |
52  * | 6 | @c kOff | Disables the corresponding sink |
53  *
54  * @par ASCII priority diagram
55  *
56  * @verbatim
57  * higher severity -> kFatal (throws)
58  * kError
59  * kWarn <- kDetailLevel (default): adds {file:line}
60  * kInfo
61  * kDebug
62  * kTrace
63  * lower severity -> kOff (sink disabled)
64  * @endverbatim
65  *
66  * @par Compile-time gating
67  * - @c VLINK_LOG_LEVEL @c =N strips levels below @c N at compile time (zero overhead).
68  * - @c VLINK_LOG_DETAIL_LEVEL @c =N changes the level at which file/line is appended.
69  * - @c VLINK_LOG_DISABLE_SHORT removes the @c VLOG_* / @c MLOG_* / @c CLOG_* / @c SLOG_* aliases.
70  *
71  * @par Formatting cheat sheet
72  *
73  * | Need | Snippet |
74  * | --------------------------------- | ------------------------------------------------------ |
75  * | Hex with 4 digits | @c VLOG_I(VLINK_LOG_HEX(4), value) |
76  * | Inline hex inside @c SLOG_* | @c SLOG_I @c << VLINK_LOG_HEXSS(4) @c << value |
77  * | Gate around expensive log args | @c if @c (VLINK_LOG_IF_D) @c { ... @c } |
78  *
79  * @par Example
80  * @code
81  * vlink::Logger::init("my_app", "/var/log/my_app.log");
82  * vlink::Logger::set_console_level(vlink::Logger::kInfo);
83  *
84  * VLOG_I("node started, id=", node_id);
85  * MLOG_W("temperature is {} C", temp);
86  * CLOG_E("errno=%d", errno);
87  * SLOG_D << "values: " << a << " " << b;
88  * @endcode
89  *
90  * @note @c kFatal messages call @c Logger::flush and then throw @c Exception::RuntimeError so
91  * the application can perform a controlled shutdown. Backends include spdlog, quill,
92  * DLT, Android logcat, QNX slog2 and kmsg depending on build options.
93  */
94 
95 #pragma once
96 
97 #include <cstdio>
98 #include <iomanip>
99 #include <iostream>
100 #include <memory>
101 #include <string>
102 #include <string_view>
103 #include <type_traits>
104 #include <utility>
105 
106 #include "./exception.h"
107 #include "./fast_stream.h"
108 #include "./format.h"
109 #include "./functional.h"
110 #include "./macros.h"
111 
112 namespace vlink {
113 
114 /**
115  * @class Logger
116  * @brief Global singleton logger with four formatting styles and independently configurable sinks.
117  *
118  * @details
119  * Construct exactly once via @c Logger::init; subsequent calls reconfigure the existing instance.
120  * The console sink is always enabled; the file sink activates when @c log_path is non-empty.
121  * Logging entry points are macros that wrap the public @c print_* templates and forward a
122  * compile-time @c Level so the bodies disappear when the level is below @c kMinimumLevel.
123  */
124 class VLINK_EXPORT Logger final {
125  public:
126  /**
127  * @brief Internal output style tag used by the @c print_* family.
128  *
129  * @details
130  * Callers normally interact with styles via macros; the enum is exposed for completeness.
131  */
132  enum Style : uint8_t {
133  kStreamStyle = 0, ///< Stream composition via @c FastStream operator<<.
134  kFormatStyle = 1, ///< Brace placeholders via @c vlink::format.
135  kCStyle = 2, ///< printf-style formatting via @c std::snprintf.
136  };
137 
138  /**
139  * @brief Message severity level.
140  *
141  * @details
142  * Lower numerical values are less severe. @c kOff is a sentinel that disables a sink.
143  */
144  enum Level : uint8_t {
145  kTrace = 0, ///< Verbose tracing.
146  kDebug = 1, ///< Developer diagnostics.
147  kInfo = 2, ///< Normal operational message.
148  kWarn = 3, ///< Recoverable but unusual condition.
149  kError = 4, ///< Recoverable error.
150  kFatal = 5, ///< Unrecoverable; throws @c Exception::RuntimeError.
151  kOff = 6, ///< Disable sink.
152  };
153 
154  /**
155  * @brief Compile-time minimum severity level; messages below this are stripped.
156  *
157  * @details
158  * Override by defining @c VLINK_LOG_LEVEL before including this header. Defaults to
159  * @c kTrace so every level is emitted by default.
160  */
161 #ifdef VLINK_LOG_LEVEL
162  static constexpr uint8_t kMinimumLevel = VLINK_LOG_LEVEL;
163 #else
164  static constexpr uint8_t kMinimumLevel = kTrace;
165 #endif
166 
167  /**
168  * @brief Severity threshold at and above which @c {file:line} is prepended to messages.
169  *
170  * @details
171  * Override by defining @c VLINK_LOG_DETAIL_LEVEL before including this header. Defaults to
172  * @c kWarn.
173  */
174 #ifdef VLINK_LOG_DETAIL_LEVEL
175  static constexpr uint8_t kDetailLevel = VLINK_LOG_DETAIL_LEVEL;
176 #else
177  static constexpr uint8_t kDetailLevel = kWarn;
178 #endif
179 
180  /**
181  * @brief Size of the thread-local C-style format buffer in bytes.
182  *
183  * @details
184  * Messages longer than @c kLocalBufferSize @c - @c 1 characters are silently truncated.
185  */
186  static constexpr int kLocalBufferSize = 4096;
187 
188  /**
189  * @brief Signature for custom console / file sink callbacks.
190  *
191  * @details
192  * Invoked synchronously from the logging thread; the @c std::string_view is valid only for
193  * the duration of the call.
194  */
195  using Callback = MoveFunction<void(Level, std::string_view)>;
196 
197  /**
198  * @brief Carries the source file name and line number for the detail prefix.
199  *
200  * @details
201  * Built automatically by @c VLINK_LOG_GET_DETAIL when the message level reaches
202  * @c kDetailLevel.
203  */
204  using DetailInfo = std::pair<std::string_view, int>;
205 
206  /**
207  * @brief Sentinel type indicating no detail prefix is attached.
208  *
209  * @details
210  * Used to avoid capturing @c __FILE__ / @c __LINE__ for messages below @c kDetailLevel.
211  */
212  struct NoDetail {};
213 
214  /**
215  * @brief Initialises the logger singleton.
216  *
217  * @details
218  * Must be invoked before any logging macros. Subsequent calls reconfigure the singleton.
219  * Provide a non-empty @p log_path to activate the file sink.
220  *
221  * @param app_name Application name embedded in log output. Default: empty.
222  * @param log_path Absolute path for the file sink. Default: empty (no file sink).
223  */
224  static void init(const std::string& app_name = "", const std::string& log_path = "") noexcept;
225 
226  /**
227  * @brief Returns the global logger instance.
228  *
229  * @return Reference to the singleton.
230  */
231  static Logger& get() noexcept;
232 
233  /**
234  * @brief Flushes every active sink.
235  *
236  * @details
237  * Useful before abnormal termination. Invoked automatically before a @c kFatal message
238  * throws.
239  */
240  static void flush() noexcept;
241 
242  /**
243  * @brief Installs a custom console sink callback replacing the built-in console writer.
244  *
245  * @param callback Handler called with @c (level, @c message_view) for each record.
246  */
247  static void register_console_handler(Callback&& callback) noexcept;
248 
249  /**
250  * @brief Installs a custom file sink callback replacing the built-in file writer.
251  *
252  * @param callback Handler called with @c (level, @c message_view) for each record.
253  */
254  static void register_file_handler(Callback&& callback) noexcept;
255 
256  /**
257  * @brief Sets the minimum severity for the console sink; pass @c kOff to mute it.
258  *
259  * @param level Minimum output level.
260  */
261  static void set_console_level(Level level) noexcept;
262 
263  /**
264  * @brief Sets the minimum severity for the file sink; pass @c kOff to mute it.
265  *
266  * @param level Minimum output level.
267  */
268  static void set_file_level(Level level) noexcept;
269 
270  /**
271  * @brief Enables or disables ANSI colour / formatting on the console sink.
272  *
273  * @param enable @c true to keep ANSI escapes (default), @c false for plain text.
274  */
275  static void set_console_fmt_enable(bool enable) noexcept;
276 
277  /**
278  * @brief Returns the current console sink severity threshold.
279  *
280  * @return Current level.
281  */
282  [[nodiscard]] static Level get_console_level() noexcept;
283 
284  /**
285  * @brief Returns the current file sink severity threshold.
286  *
287  * @return Current level.
288  */
289  [[nodiscard]] static Level get_file_level() noexcept;
290 
291  /**
292  * @brief Returns whether ANSI colour codes are enabled on the console sink.
293  *
294  * @return @c true when ANSI escapes are emitted.
295  */
296  [[nodiscard]] static bool get_console_fmt_enable() noexcept;
297 
298  /**
299  * @brief Sets @c std::ios_base format flags applied to stream-style records.
300  *
301  * @param flags Stream format flags.
302  */
303  static void set_stream_flag(std::ios_base::fmtflags flags) noexcept;
304 
305  /**
306  * @brief Sets the floating-point precision for stream-style records.
307  *
308  * @param precision Precision passed to @c std::setprecision.
309  */
310  static void set_stream_precision(int precision) noexcept;
311 
312  /**
313  * @brief Sets the minimum field width for stream-style records.
314  *
315  * @param width Field width passed to @c std::setw.
316  */
317  static void set_stream_width(int width) noexcept;
318 
319  /**
320  * @brief Returns the stream format flags currently applied to stream-style records.
321  *
322  * @return Format flags.
323  */
324  [[nodiscard]] static std::ios_base::fmtflags get_stream_flag() noexcept;
325 
326  /**
327  * @brief Returns the floating-point precision used for stream-style records.
328  *
329  * @return Precision value.
330  */
331  [[nodiscard]] static int get_stream_precision() noexcept;
332 
333  /**
334  * @brief Returns the field width used for stream-style records.
335  *
336  * @return Width value.
337  */
338  [[nodiscard]] static int get_stream_width() noexcept;
339 
340  /**
341  * @brief Enables a ring-buffer backtrace of the most recent @p size records.
342  *
343  * @param size Capacity of the backtrace ring buffer.
344  */
345  static void enable_backtrace(size_t size) noexcept;
346 
347  /**
348  * @brief Disables backtrace capture and discards the ring buffer.
349  */
350  static void disable_backtrace() noexcept;
351 
352  /**
353  * @brief Flushes the backtrace ring buffer to the active sinks.
354  */
355  static void dump_backtrace() noexcept;
356 
357  /**
358  * @brief Reports whether the logger is currently writing a record.
359  *
360  * @return @c true while a write is in progress.
361  */
362  [[nodiscard]] static bool is_busy() noexcept;
363 
364  /**
365  * @brief Reports whether a record at @p level would currently be emitted.
366  *
367  * @details
368  * Use the result to gate expensive argument computation before a macro call.
369  *
370  * @param level Severity level under test.
371  * @return @c true when the level passes either sink threshold.
372  */
373  [[nodiscard]] static bool is_writable(Level level) noexcept;
374 
375  /**
376  * @brief Strips a path down to its final filename component at compile time.
377  *
378  * @param path Source path, typically @c __FILE__.
379  * @return View covering the filename portion.
380  */
381  [[nodiscard]] static constexpr std::string_view extract_filename(std::string_view path) noexcept;
382 
383  /**
384  * @brief Stream-style entry point (used by @c VLOG_* / @c print).
385  *
386  * @details
387  * Returns immediately when @c should_log<LevelT>() is @c false. Otherwise streams @p args
388  * into a thread-local @c FastStream and hands the resulting view to the sinks.
389  *
390  * @tparam LevelT Compile-time severity.
391  * @tparam DetailT Either @c DetailInfo or @c NoDetail.
392  * @tparam ArgsT Stream argument types.
393  * @param detail Source location info or @c NoDetail{}.
394  * @param args Values to stream.
395  */
396  template <Level LevelT, typename DetailT, typename... ArgsT>
397  static void print_stream_style(DetailT&& detail, ArgsT&&... args);
398 
399  /**
400  * @brief Placeholder-style entry point (used by @c MLOG_*).
401  *
402  * @tparam LevelT Compile-time severity.
403  * @tparam DetailT Either @c DetailInfo or @c NoDetail.
404  * @tparam ArgsT Format argument types.
405  * @param detail Source location info or @c NoDetail{}.
406  * @param format Format string with @c {} placeholders.
407  * @param args Format arguments.
408  */
409  template <Level LevelT, typename DetailT, typename... ArgsT>
410  static void print_format_style(DetailT&& detail, format::format_string<ArgsT...> format, ArgsT&&... args);
411 
412  /**
413  * @brief printf-style entry point (used by @c CLOG_*).
414  *
415  * @tparam LevelT Compile-time severity.
416  * @tparam DetailT Either @c DetailInfo or @c NoDetail.
417  * @tparam FormatT Format string type, typically @c const @c char*.
418  * @tparam ArgsT printf argument types.
419  * @param detail Source location info or @c NoDetail{}.
420  * @param format printf-style format string.
421  * @param args printf arguments.
422  */
423  template <Logger::Level LevelT, typename DetailT, typename FormatT, typename... ArgsT>
424  static void print_c_style(DetailT&& detail, FormatT&& format, ArgsT&&... args);
425 
426  /**
427  * @brief Convenience stream-style entry point without source location.
428  *
429  * @tparam LevelT Compile-time severity.
430  * @tparam ArgsT Stream argument types.
431  * @param args Values to stream.
432  */
433  template <Level LevelT, typename... ArgsT>
434  static void print(ArgsT&&... args);
435 
436  /**
437  * @class WrapperStream
438  * @brief RAII helper backing @c SLOG_*; collects tokens and flushes on destruction.
439  *
440  * @details
441  * When @c kIsEnabled is @c false at the chosen level the type and its methods compile to
442  * nothing, so disabled-level call sites have zero runtime overhead.
443  *
444  * @tparam LevelT Compile-time severity level.
445  */
446  template <Logger::Level LevelT>
447  class WrapperStream final {
448  public:
449  /**
450  * @brief Static gate indicating whether the wrapper emits at the chosen level.
451  */
452  static constexpr bool kIsEnabled = (LevelT >= kMinimumLevel && LevelT < Logger::kOff);
453 
454  explicit WrapperStream(Logger::NoDetail) noexcept {
455  if constexpr (kIsEnabled) {
456  if (should_log<LevelT>()) {
457  enabled_ = true;
458  stream_ = &Logger::get_local_stream();
459  }
460  }
461  }
462 
463  explicit WrapperStream(DetailInfo&& detail) noexcept {
464  if constexpr (kIsEnabled) {
465  if (should_log<LevelT>()) {
466  enabled_ = true;
467  stream_ = &Logger::get_local_stream();
468 
469  push_detail_to_stream(detail, *stream_);
470  }
471  }
472  }
473 
474  WrapperStream(WrapperStream&& other) noexcept : stream_(other.stream_), enabled_(other.enabled_) {
475  other.stream_ = nullptr;
476  other.enabled_ = false;
477  }
478 
480 
481  ~WrapperStream() noexcept(LevelT != Level::kFatal) {
482  if constexpr (kIsEnabled) {
483  if (enabled_) {
484  finalize_log<LevelT>(stream_->take_view());
485  }
486  }
487  }
488 
489  template <typename T>
490  WrapperStream& operator<<(T&& t) noexcept {
491  if constexpr (kIsEnabled) {
492  if (enabled_) {
493  *stream_ << std::forward<T>(t);
494  }
495  }
496 
497  return *this;
498  }
499 
500  private:
502 
503  FastStream* stream_{nullptr};
504  bool enabled_{false};
505  };
506 
507  private:
508  Logger() noexcept;
509 
510  ~Logger() noexcept;
511 
512  template <Level LevelT>
513  static bool should_log() noexcept;
514 
515  template <Level LevelT>
516  static void finalize_log(std::string_view log_view);
517 
518  template <typename DetailT>
519  static void push_detail_to_stream(DetailT&& detail, FastStream& stream) noexcept;
520 
521  template <typename DetailT>
522  static std::string_view format_with_detail(DetailT&& detail, const char* msg, int len) noexcept;
523 
524  static char* get_local_buffer() noexcept;
525 
526  static FastStream& get_local_stream() noexcept;
527 
528  void write_to_console(Level level, std::string_view log) noexcept;
529 
530  void write_to_file(Level level, std::string_view log) noexcept;
531 
532  struct Impl;
533  std::unique_ptr<Impl> impl_;
534 
535  template <Logger::Level LevelT>
536  friend class WrapperStream;
537 
539 
541 };
542 
543 ////////////////////////////////////////////////////////////////
544 /// Details
545 ////////////////////////////////////////////////////////////////
546 
547 inline constexpr std::string_view Logger::extract_filename(std::string_view path) noexcept {
548  auto pos = path.find_last_of("/\\");
549  return (pos == std::string_view::npos) ? path : path.substr(pos + 1);
550 }
551 
552 template <Logger::Level LevelT, typename DetailT, typename... ArgsT>
553 inline void Logger::print_stream_style([[maybe_unused]] DetailT&& detail, [[maybe_unused]] ArgsT&&... args) {
554  if (!should_log<LevelT>()) {
555  return;
556  }
557 
558  auto& stream = get_local_stream();
559 
560  if constexpr (std::is_same_v<std::decay_t<DetailT>, DetailInfo>) {
561  push_detail_to_stream(detail, stream);
562  }
563 
564  (void)(stream << ... << args);
565 
566  finalize_log<LevelT>(stream.take_view());
567 }
568 
569 template <Logger::Level LevelT, typename DetailT, typename... ArgsT>
570 inline void Logger::print_format_style([[maybe_unused]] DetailT&& detail,
571  [[maybe_unused]] format::format_string<ArgsT...> format,
572  [[maybe_unused]] ArgsT&&... args) {
573  if (!should_log<LevelT>()) {
574  return;
575  }
576 
577  std::string_view log_view;
578 
579  auto* local_buffer = get_local_buffer();
580  auto result = format::format_to_n(local_buffer, kLocalBufferSize - 1, format, std::forward<ArgsT>(args)...);
581  auto written = static_cast<int>(result.out - local_buffer);
582 
583  local_buffer[written] = '\0';
584 
585  log_view = format_with_detail(detail, local_buffer, written);
586 
587  finalize_log<LevelT>(log_view);
588 }
589 
590 template <Logger::Level LevelT, typename DetailT, typename FormatT, typename... ArgsT>
591 inline void Logger::print_c_style([[maybe_unused]] DetailT&& detail, [[maybe_unused]] FormatT&& format,
592  [[maybe_unused]] ArgsT&&... args) {
593  if (!should_log<LevelT>()) {
594  return;
595  }
596 
597  std::string_view log_view;
598 
599  if constexpr (sizeof...(ArgsT) == 0) {
600  auto& stream = get_local_stream();
601 
602  if constexpr (std::is_same_v<std::decay_t<DetailT>, DetailInfo>) {
603  push_detail_to_stream(detail, stream);
604  }
605 
606  stream << format;
607  log_view = stream.take_view();
608  } else {
609  auto* local_buffer = get_local_buffer();
610  auto written = std::snprintf(local_buffer, kLocalBufferSize - 1, format, args...);
611 
612  if VUNLIKELY (written < 0) {
613  written = 0;
614  } else if VUNLIKELY (written > kLocalBufferSize - 1) {
615  written = kLocalBufferSize - 1;
616  }
617 
618  log_view = format_with_detail(detail, local_buffer, written);
619  }
620 
621  finalize_log<LevelT>(log_view);
622 }
623 
624 template <Logger::Level LevelT, typename... ArgsT>
625 inline void Logger::print([[maybe_unused]] ArgsT&&... args) {
626  print_stream_style<LevelT>(NoDetail{}, args...);
627 }
628 
629 template <Logger::Level LevelT>
630 inline bool Logger::should_log() noexcept {
631  if constexpr (LevelT < Logger::kMinimumLevel || LevelT >= Logger::kOff) {
632  return false;
633  } else if constexpr (LevelT == Logger::kFatal) {
634  return true;
635  } else {
636  return Logger::is_writable(LevelT);
637  }
638 }
639 
640 template <Logger::Level LevelT>
641 inline void Logger::finalize_log(std::string_view log_view) {
642  Logger& instance = Logger::get();
643 
644  instance.write_to_console(LevelT, log_view);
645  instance.write_to_file(LevelT, log_view);
646 
647  if constexpr (LevelT == Logger::kFatal) {
648  Logger::flush();
649  throw Exception::RuntimeError(std::string(log_view));
650  }
651 }
652 
653 template <typename DetailT>
654 inline void Logger::push_detail_to_stream(DetailT&& detail, FastStream& stream) noexcept {
655  auto& [file, line] = detail;
656  stream << "{" << file << ":" << line << "} ";
657 }
658 
659 template <typename DetailT>
660 inline std::string_view Logger::format_with_detail(DetailT&& detail, const char* msg, int len) noexcept {
661  if constexpr (std::is_same_v<std::decay_t<DetailT>, Logger::DetailInfo>) {
662  auto& stream = Logger::get_local_stream();
663 
664  push_detail_to_stream(detail, stream);
665 
666  if VLIKELY (len > 0) {
667  stream.write_raw(msg, static_cast<size_t>(len));
668  }
669 
670  return stream.take_view();
671  } else {
672  if VLIKELY (len > 0) {
673  return std::string_view(msg, static_cast<size_t>(len));
674  }
675 
676  return {};
677  }
678 }
679 
680 } // namespace vlink
681 
683 
684 ////////////////////////////////////////////////////////////////
685 /// Macro Definitions
686 ////////////////////////////////////////////////////////////////
687 
688 #define VLINK_LOG_GET_DETAIL(level) \
689  ([]() -> auto { \
690  if constexpr ((level) >= VLinkLogger::kDetailLevel) { \
691  return VLinkLogger::DetailInfo{VLinkLogger::extract_filename(__FILE__), __LINE__}; \
692  } else { \
693  return VLinkLogger::NoDetail{}; \
694  } \
695  })()
696 
697 #define VLINK_LOG_HEX(offset) std::hex, std::uppercase, std::setw(offset), std::setfill('0')
698 
699 #define VLINK_LOG_HEXSS(offset) std::hex << std::uppercase << std::setw(offset) << std::setfill('0')
700 
701 #define VLINK_LOG_IF_T VLinkLogger::is_writable(VLinkLogger::kTrace)
702 
703 #define VLINK_LOG_IF_D VLinkLogger::is_writable(VLinkLogger::kDebug)
704 
705 #define VLINK_LOG_IF_I VLinkLogger::is_writable(VLinkLogger::kInfo)
706 
707 #define VLINK_LOG_IF_W VLinkLogger::is_writable(VLinkLogger::kWarn)
708 
709 #define VLINK_LOG_IF_E VLinkLogger::is_writable(VLinkLogger::kError)
710 
711 #define VLINK_LOG_IF_F VLinkLogger::is_writable(VLinkLogger::kFatal)
712 
713 #define VLINK_LOG_T(...) \
714  VLinkLogger::print_stream_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
715 
716 #define VLINK_LOG_D(...) \
717  VLinkLogger::print_stream_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
718 
719 #define VLINK_LOG_I(...) \
720  VLinkLogger::print_stream_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
721 
722 #define VLINK_LOG_W(...) \
723  VLinkLogger::print_stream_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
724 
725 #define VLINK_LOG_E(...) \
726  VLinkLogger::print_stream_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
727 
728 #define VLINK_LOG_F(...) \
729  VLinkLogger::print_stream_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
730 
731 #define VLINK_MLOG_T(...) \
732  VLinkLogger::print_format_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
733 
734 #define VLINK_MLOG_D(...) \
735  VLinkLogger::print_format_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
736 
737 #define VLINK_MLOG_I(...) \
738  VLinkLogger::print_format_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
739 
740 #define VLINK_MLOG_W(...) \
741  VLinkLogger::print_format_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
742 
743 #define VLINK_MLOG_E(...) \
744  VLinkLogger::print_format_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
745 
746 #define VLINK_MLOG_F(...) \
747  VLinkLogger::print_format_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
748 
749 #define VLINK_CLOG_T(...) \
750  VLinkLogger::print_c_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
751 
752 #define VLINK_CLOG_D(...) \
753  VLinkLogger::print_c_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
754 
755 #define VLINK_CLOG_I(...) \
756  VLinkLogger::print_c_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
757 
758 #define VLINK_CLOG_W(...) \
759  VLinkLogger::print_c_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
760 
761 #define VLINK_CLOG_E(...) \
762  VLinkLogger::print_c_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
763 
764 #define VLINK_CLOG_F(...) \
765  VLinkLogger::print_c_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
766 
767 #define VLINK_SLOG_T VLinkLogger::WrapperStream<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace))
768 
769 #define VLINK_SLOG_D VLinkLogger::WrapperStream<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug))
770 
771 #define VLINK_SLOG_I VLinkLogger::WrapperStream<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo))
772 
773 #define VLINK_SLOG_W VLinkLogger::WrapperStream<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn))
774 
775 #define VLINK_SLOG_E VLinkLogger::WrapperStream<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError))
776 
777 #define VLINK_SLOG_F VLinkLogger::WrapperStream<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal))
778 
779 #ifndef VLINK_LOG_DISABLE_SHORT
780 
781 #define VLOG_T(...) VLINK_LOG_T(__VA_ARGS__)
782 
783 #define VLOG_D(...) VLINK_LOG_D(__VA_ARGS__)
784 
785 #define VLOG_I(...) VLINK_LOG_I(__VA_ARGS__)
786 
787 #define VLOG_W(...) VLINK_LOG_W(__VA_ARGS__)
788 
789 #define VLOG_E(...) VLINK_LOG_E(__VA_ARGS__)
790 
791 #define VLOG_F(...) VLINK_LOG_F(__VA_ARGS__)
792 
793 #define CLOG_T(...) VLINK_CLOG_T(__VA_ARGS__)
794 
795 #define CLOG_D(...) VLINK_CLOG_D(__VA_ARGS__)
796 
797 #define CLOG_I(...) VLINK_CLOG_I(__VA_ARGS__)
798 
799 #define CLOG_W(...) VLINK_CLOG_W(__VA_ARGS__)
800 
801 #define CLOG_E(...) VLINK_CLOG_E(__VA_ARGS__)
802 
803 #define CLOG_F(...) VLINK_CLOG_F(__VA_ARGS__)
804 
805 #define MLOG_T(...) VLINK_MLOG_T(__VA_ARGS__)
806 
807 #define MLOG_D(...) VLINK_MLOG_D(__VA_ARGS__)
808 
809 #define MLOG_I(...) VLINK_MLOG_I(__VA_ARGS__)
810 
811 #define MLOG_W(...) VLINK_MLOG_W(__VA_ARGS__)
812 
813 #define MLOG_E(...) VLINK_MLOG_E(__VA_ARGS__)
814 
815 #define MLOG_F(...) VLINK_MLOG_F(__VA_ARGS__)
816 
817 #define SLOG_T VLINK_SLOG_T
818 
819 #define SLOG_D VLINK_SLOG_D
820 
821 #define SLOG_I VLINK_SLOG_I
822 
823 #define SLOG_W VLINK_SLOG_W
824 
825 #define SLOG_E VLINK_SLOG_E
826 
827 #define SLOG_F VLINK_SLOG_F
828 
829 #endif
Thin final wrappers around the standard exception hierarchy used by VLink.
Allocation-light std::ostream backed by a growable string buffer.
Minimal heap-free {} placeholder formatter for the logger hot path.
Pool-backed type-erased callables: copyable vlink::Function and move-only vlink::MoveFunction.
Cross-platform macros for visibility, branch hints, copy prevention, singletons and string helpers.
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLINK_SINGLETON_CHECK(classname)
Embeds a static check that enforces one-instance-per-process for classname.
Definition: macros.h:192
#define VLINK_EXPORT
Definition: macros.h:81
#define VLIKELY(...)
Short alias for VLINK_LIKELY.
Definition: macros.h:284
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174