VLink 2.0.0
A high-performance communication middleware
载入中...
搜索中...
未找到
logger.h
浏览该文件的文档.
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 Global singleton logger with three output styles and pluggable backends.
27 *
28 * @details
29 * @c Logger is the central logging facility in VLink. It is a singleton accessed via
30 * @c Logger::get() and initialised once with @c Logger::init(). Log messages can be
31 * written to a console sink and/or a file sink, each with an independently configured
32 * minimum level.
33 *
34 * Output styles:
35 *
36 * | Style | Syntax | Notes |
37 * | -------------------- | ------------------------------ | ---------------------------------------------- |
38 * | Stream style (LOG) | @c VLOG_I("x=", x) | Uses @c FastStream operator<<, zero allocation |
39 * | Format style (MLOG) | @c MLOG_I("x={}", x) | Uses VLink @c format::format_to_n |
40 * | C style (CLOG) | @c CLOG_I("x=%d", x) | Uses @c std::snprintf |
41 * | RAII stream (SLOG) | @c SLOG_I << "x=" << x | WrapperStream, flushed on destruction |
42 *
43 * Log levels:
44 *
45 * | Value | Name | Use case |
46 * | ----- | ------- | ------------------------------------------ |
47 * | 0 | kTrace | Verbose internals |
48 * | 1 | kDebug | Developer diagnostics |
49 * | 2 | kInfo | Normal operational messages |
50 * | 3 | kWarn | Unusual but recoverable conditions |
51 * | 4 | kError | Errors that may affect operation |
52 * | 5 | kFatal | Unrecoverable errors; throws RuntimeError |
53 * | 6 | kOff | Disables all output |
54 *
55 * Detail annotation:
56 * When the log level is >= @c kDetailLevel (default: @c kWarn), the macro automatically
57 * prepends @c {filename:line} to the message to aid in debugging.
58 *
59 * Compile-time filtering:
60 * - Define @c VLINK_LOG_LEVEL=N to strip levels below @c N at compile time (zero overhead).
61 * - Define @c VLINK_LOG_DETAIL_LEVEL=N to change the threshold at which file/line is shown.
62 * - Define @c VLINK_LOG_DISABLE_SHORT to suppress the short @c VLOG_* aliases.
63 *
64 * Backtrace support:
65 * When enabled via @c enable_backtrace(n), the last @p n log messages are kept in a
66 * ring buffer and can be flushed on demand with @c dump_backtrace().
67 *
68 * Backend support:
69 * The logger dispatches to spdlog, quill, DLT (automotive), Android logcat, QNX slog2,
70 * or kmsg depending on compile-time configuration. Custom backends can be registered
71 * with @c register_console_handler() / @c register_file_handler().
72 *
73 * @note
74 * - @c kFatal logs flush the logger and then throw @c Exception::RuntimeError.
75 * - The @c WrapperStream class is template-based; unused log levels are compiled away.
76 *
77 * @par Example
78 * @code
79 * vlink::Logger::init("my_app", "/var/log/my_app.log");
80 * vlink::Logger::set_console_level(vlink::Logger::kInfo);
81 *
82 * VLOG_I("node started, id=", node_id);
83 * MLOG_W("temperature is {} C", temp);
84 * CLOG_E("errno=%d", errno);
85 * SLOG_D << "values: " << a << " " << b;
86 * @endcode
87 */
88
89#pragma once
90
91#include <cstdio>
92#include <functional>
93#include <iomanip>
94#include <iostream>
95#include <memory>
96#include <string>
97#include <string_view>
98#include <type_traits>
99#include <utility>
100
101#include "./exception.h"
102#include "./fast_stream.h"
103#include "./format.h"
104#include "./macros.h"
105
106namespace vlink {
107
108/**
109 * @class Logger
110 * @brief Global singleton logger supporting three output styles and configurable log levels.
111 *
112 * @details
113 * Construct the singleton with @c Logger::init() once at application startup.
114 * Use the @c VLOG_*, @c MLOG_*, @c CLOG_* or @c SLOG_* macros for logging.
115 */
116class VLINK_EXPORT Logger final {
117 public:
118 /**
119 * @brief Output style selector (used internally by the print_* family).
120 *
121 * @details
122 * Determines how format arguments are converted to a string.
123 * Users interact with styles through macros rather than this enum directly.
124 */
125 enum Style : uint8_t {
126 kStreamStyle = 0, ///< operator<< stream composition via FastStream
127 kFormatStyle = 1, ///< Python-style {} placeholders via vlink::format
128 kCStyle = 2, ///< printf-style %d/%s via std::snprintf
129 };
130
131 /**
132 * @brief Severity level for log messages.
133 *
134 * @details
135 * Levels are ordered from least severe (kTrace) to most severe (kFatal).
136 * kOff disables the corresponding sink entirely.
137 *
138 * | Value | Name | Meaning |
139 * | ----- | ------- | -------------------------------------------- |
140 * | 0 | kTrace | Verbose tracing |
141 * | 1 | kDebug | Developer diagnostics |
142 * | 2 | kInfo | Normal operational messages |
143 * | 3 | kWarn | Unusual but recoverable conditions |
144 * | 4 | kError | Recoverable errors |
145 * | 5 | kFatal | Throws RuntimeError after logging |
146 * | 6 | kOff | Disable sink |
147 */
148 enum Level : uint8_t {
151 kInfo = 2,
152 kWarn = 3,
155 kOff = 6,
156 };
157
158 /**
159 * @brief Compile-time minimum log level.
160 *
161 * @details
162 * Messages with level < @c kMinimumLevel are compiled away completely.
163 * Override by defining @c VLINK_LOG_LEVEL before including this header.
164 * Defaults to @c kTrace (all messages enabled).
165 */
166#ifdef VLINK_LOG_LEVEL
167 static constexpr uint8_t kMinimumLevel = VLINK_LOG_LEVEL;
168#else
169 static constexpr uint8_t kMinimumLevel = kTrace;
170#endif
171
172 /**
173 * @brief Threshold above which file and line information is appended to messages.
174 *
175 * @details
176 * When the message level >= @c kDetailLevel, the macro prepends @c {file:line}
177 * to the log string. Override by defining @c VLINK_LOG_DETAIL_LEVEL.
178 * Defaults to @c kWarn.
179 */
180#ifdef VLINK_LOG_DETAIL_LEVEL
181 static constexpr uint8_t kDetailLevel = VLINK_LOG_DETAIL_LEVEL;
182#else
183 static constexpr uint8_t kDetailLevel = kWarn;
184#endif
185
186 /**
187 * @brief Size of the thread-local C-style format buffer in bytes.
188 *
189 * @details
190 * Used by @c print_c_style() and @c print_format_style(). Messages longer than
191 * @c kLocalBufferSize - 1 characters are silently truncated.
192 */
193 static constexpr int kLocalBufferSize = 4096;
194
195 /**
196 * @brief Callback type for custom console or file log handlers.
197 *
198 * @details
199 * Registered handlers are called synchronously from the logging thread.
200 * The @c std::string_view is valid only for the duration of the call.
201 */
202 using Callback = std::function<void(Level, std::string_view)>;
203
204 /**
205 * @brief Carries the source file name and line number for detail annotation.
206 *
207 * @details
208 * Created automatically by @c VLINK_LOG_GET_DETAIL when the message level is
209 * >= @c kDetailLevel.
210 */
211 using DetailInfo = std::pair<std::string_view, int>;
212
213 /**
214 * @brief Sentinel type indicating that no file/line detail is attached.
215 *
216 * @details
217 * Used for levels below @c kDetailLevel to avoid capturing __FILE__ and __LINE__.
218 */
219 struct NoDetail {};
220
221 /**
222 * @brief Initialises the logger singleton.
223 *
224 * @details
225 * Must be called before any log macros are invoked. Safe to call multiple times;
226 * subsequent calls reconfigure the logger. If @p log_path is non-empty, the file
227 * sink is opened at that path.
228 *
229 * @param app_name Application name embedded in log output. Default: empty string.
230 * @param log_path Absolute path for the log file. Default: no file sink.
231 */
232 static void init(const std::string& app_name = "", const std::string& log_path = "") noexcept;
233
234 /**
235 * @brief Returns the logger singleton instance.
236 *
237 * @details
238 * The singleton is created on first use. It is safe to call @c get() from any thread
239 * after @c init() has been called.
240 *
241 * @return Reference to the global @c Logger instance.
242 */
243 static Logger& get() noexcept;
244
245 /**
246 * @brief Flushes all buffered log messages to the active sinks.
247 *
248 * @details
249 * Useful before abnormal termination to ensure messages are not lost.
250 * Called automatically for @c kFatal messages.
251 */
252 static void flush() noexcept;
253
254 /**
255 * @brief Registers a custom handler for console log output.
256 *
257 * @details
258 * When set, the provided callback is invoked instead of (or in addition to) the
259 * built-in console sink. Replaces any previously registered console handler.
260 *
261 * @param callback Handler called with (level, message_view) for each log record.
262 */
263 static void register_console_handler(Callback&& callback) noexcept;
264
265 /**
266 * @brief Registers a custom handler for file log output.
267 *
268 * @details
269 * When set, the provided callback is invoked instead of (or in addition to) the
270 * built-in file sink. Replaces any previously registered file handler.
271 *
272 * @param callback Handler called with (level, message_view) for each log record.
273 */
274 static void register_file_handler(Callback&& callback) noexcept;
275
276 /**
277 * @brief Sets the minimum level for the console sink.
278 *
279 * @details
280 * Messages with level < @p level are not written to the console.
281 * Pass @c kOff to disable the console sink entirely.
282 *
283 * @param level New minimum console output level.
284 */
285 static void set_console_level(Level level) noexcept;
286
287 /**
288 * @brief Sets the minimum level for the file sink.
289 *
290 * @details
291 * Messages with level < @p level are not written to the log file.
292 * Pass @c kOff to disable the file sink entirely.
293 *
294 * @param level New minimum file output level.
295 */
296 static void set_file_level(Level level) noexcept;
297
298 /**
299 * @brief Enables or disables ANSI colour/format codes in console output.
300 *
301 * @param enable @c true to enable formatting codes (default), @c false for plain text.
302 */
303 static void set_console_fmt_enable(bool enable) noexcept;
304
305 /**
306 * @brief Returns the current minimum level for the console sink.
307 *
308 * @return Current console log level.
309 */
310 [[nodiscard]] static Level get_console_level() noexcept;
311
312 /**
313 * @brief Returns the current minimum level for the file sink.
314 *
315 * @return Current file log level.
316 */
317 [[nodiscard]] static Level get_file_level() noexcept;
318
319 /**
320 * @brief Returns whether ANSI colour/format codes are enabled for console output.
321 *
322 * @return @c true if formatting is enabled.
323 */
324 [[nodiscard]] static bool get_console_fmt_enable() noexcept;
325
326 /**
327 * @brief Sets @c std::ios_base format flags applied to stream-style messages.
328 *
329 * @details
330 * The flags are applied to the thread-local @c FastStream before each message.
331 * For example, pass @c std::ios::hex to print integers in hexadecimal.
332 *
333 * @param flags Format flags to set.
334 */
335 static void set_stream_flag(std::ios_base::fmtflags flags) noexcept;
336
337 /**
338 * @brief Sets the floating-point precision for stream-style messages.
339 *
340 * @param precision Number of significant digits (or decimal places depending on format flag).
341 */
342 static void set_stream_precision(int precision) noexcept;
343
344 /**
345 * @brief Sets the output field width for stream-style messages.
346 *
347 * @param width Minimum field width in characters.
348 */
349 static void set_stream_width(int width) noexcept;
350
351 /**
352 * @brief Returns the @c std::ios_base format flags currently applied to stream output.
353 *
354 * @return Current stream format flags.
355 */
356 [[nodiscard]] static std::ios_base::fmtflags get_stream_flag() noexcept;
357
358 /**
359 * @brief Returns the floating-point precision currently used for stream output.
360 *
361 * @return Current precision value.
362 */
363 [[nodiscard]] static int get_stream_precision() noexcept;
364
365 /**
366 * @brief Returns the field width currently used for stream output.
367 *
368 * @return Current field width.
369 */
370 [[nodiscard]] static int get_stream_width() noexcept;
371
372 /**
373 * @brief Enables a ring-buffer backtrace of the last @p size log messages.
374 *
375 * @details
376 * When enabled, the last @p size messages are retained in memory regardless of
377 * the current log level, and can be flushed with @c dump_backtrace().
378 *
379 * @param size Number of messages to retain in the backtrace ring buffer.
380 */
381 static void enable_backtrace(size_t size) noexcept;
382
383 /**
384 * @brief Disables backtrace collection and clears the ring buffer.
385 */
386 static void disable_backtrace() noexcept;
387
388 /**
389 * @brief Flushes the backtrace ring buffer to the active sinks.
390 *
391 * @details
392 * Emits all retained backtrace messages (if any) to the console and file sinks
393 * at their original log levels. Useful just before an abort or fatal handler.
394 */
395 static void dump_backtrace() noexcept;
396
397 /**
398 * @brief Returns @c true if the logger is currently busy writing a message.
399 *
400 * @details
401 * Useful for asynchronous backends to check whether the logger can accept more work.
402 *
403 * @return @c true if a write is in progress.
404 */
405 [[nodiscard]] static bool is_busy() noexcept;
406
407 /**
408 * @brief Returns @c true if a message at @p level would be written to at least one sink.
409 *
410 * @details
411 * Checks both the console and file sink levels. @c kFatal always returns @c true.
412 * Call this before constructing expensive log arguments to avoid unnecessary work.
413 *
414 * @param level Level to test.
415 * @return @c true if the message would be emitted.
416 */
417 [[nodiscard]] static bool is_writable(Level level) noexcept;
418
419 /**
420 * @brief Extracts the file name component from a full path at compile time.
421 *
422 * @details
423 * Searches for the last @c '/' or @c '\\' and returns the substring after it.
424 * Used by the @c VLINK_LOG_GET_DETAIL macro to trim __FILE__.
425 *
426 * @param path Full source file path (typically @c __FILE__).
427 * @return @c string_view of just the filename portion.
428 */
429 [[nodiscard]] static constexpr std::string_view extract_filename(std::string_view path) noexcept;
430
431 /**
432 * @brief Logs using stream-style composition (operator<<).
433 *
434 * @details
435 * Called by the @c VLOG_* macros. Checks @c should_log() first; returns immediately
436 * if the level is disabled. Uses a thread-local @c FastStream to avoid heap allocations.
437 *
438 * @tparam LevelT Compile-time log level.
439 * @tparam DetailT Either @c DetailInfo (with file/line) or @c NoDetail.
440 * @tparam ArgsT Types of the stream arguments.
441 * @param detail File/line info or @c NoDetail{}.
442 * @param args Values streamed into the message via @c operator<<.
443 */
444 template <Level LevelT, typename DetailT, typename... ArgsT>
445 static void print_stream_style(DetailT&& detail, ArgsT&&... args);
446
447 /**
448 * @brief Logs using @c {} placeholder format style.
449 *
450 * @details
451 * Called by the @c MLOG_* macros. Formats the message using @c format::format_to_n
452 * into a 4096-byte thread-local buffer. Messages exceeding the buffer are truncated.
453 *
454 * @tparam LevelT Compile-time log level.
455 * @tparam DetailT Either @c DetailInfo or @c NoDetail.
456 * @tparam ArgsT Types of the format arguments.
457 * @param detail File/line info or @c NoDetail{}.
458 * @param format Format string with @c {} placeholders.
459 * @param args Format arguments.
460 */
461 template <Level LevelT, typename DetailT, typename... ArgsT>
462 static void print_format_style(DetailT&& detail, format::format_string<ArgsT...> format, ArgsT&&... args);
463
464 /**
465 * @brief Logs using C-style printf format string.
466 *
467 * @details
468 * Called by the @c CLOG_* macros. Formats using @c std::snprintf into a 4096-byte
469 * thread-local buffer. Messages exceeding the buffer are truncated.
470 *
471 * @tparam LevelT Compile-time log level.
472 * @tparam DetailT Either @c DetailInfo or @c NoDetail.
473 * @tparam FormatT Type of the format string (typically @c const char*).
474 * @tparam ArgsT Types of the printf arguments.
475 * @param detail File/line info or @c NoDetail{}.
476 * @param format printf-style format string.
477 * @param args printf arguments.
478 */
479 template <Logger::Level LevelT, typename DetailT, typename FormatT, typename... ArgsT>
480 static void print_c_style(DetailT&& detail, FormatT&& format, ArgsT&&... args);
481
482 /**
483 * @brief Logs using stream style without file/line detail.
484 *
485 * @details
486 * Convenience wrapper that passes @c NoDetail{} to @c print_stream_style.
487 *
488 * @tparam LevelT Compile-time log level.
489 * @tparam ArgsT Types of the stream arguments.
490 * @param args Values to stream.
491 */
492 template <Level LevelT, typename... ArgsT>
493 static void print(ArgsT&&... args);
494
495 /**
496 * @class WrapperStream
497 * @brief RAII stream wrapper that accumulates tokens and flushes on destruction.
498 *
499 * @details
500 * Used by the @c SLOG_* macros to allow natural @c << chaining. The message is
501 * emitted when the temporary @c WrapperStream object goes out of scope.
502 * If the log level is disabled at compile time (@c kIsEnabled == false), all
503 * methods are compiled away and the object has zero runtime cost.
504 *
505 * @tparam LevelT Compile-time log level.
506 */
507 template <Logger::Level LevelT>
508 class WrapperStream final {
509 public:
510 /**
511 * @brief Indicates whether this level is enabled at compile time.
512 *
513 * @details
514 * If @c false, all @c operator<< calls and the destructor flush are no-ops.
515 */
516 static constexpr bool kIsEnabled = (LevelT >= kMinimumLevel && LevelT < Logger::kOff);
517
518 explicit WrapperStream(Logger::NoDetail) noexcept {
519 if constexpr (kIsEnabled) {
520 if (should_log<LevelT>()) {
521 enabled_ = true;
522 stream_ = &Logger::get_local_stream();
523 }
524 }
525 }
526
527 explicit WrapperStream(DetailInfo&& detail) noexcept {
528 if constexpr (kIsEnabled) {
529 if (should_log<LevelT>()) {
530 enabled_ = true;
531 stream_ = &Logger::get_local_stream();
532
533 push_detail_to_stream(detail, *stream_);
534 }
535 }
536 }
537
538 WrapperStream(WrapperStream&& other) noexcept : stream_(other.stream_), enabled_(other.enabled_) {
539 other.stream_ = nullptr;
540 other.enabled_ = false;
541 }
542
544
546 if constexpr (kIsEnabled) {
547 if (enabled_) {
548 finalize_log<LevelT>(stream_->take_view());
549 }
550 }
551 }
552
553 template <typename T>
554 WrapperStream& operator<<(T&& t) noexcept {
555 if constexpr (kIsEnabled) {
556 if (enabled_) {
557 *stream_ << std::forward<T>(t);
558 }
559 }
560
561 return *this;
562 }
563
564 private:
566
567 FastStream* stream_{nullptr};
568 bool enabled_{false};
569 };
570
571 private:
572 Logger() noexcept;
573
574 ~Logger() noexcept;
575
576 template <Level LevelT>
577 static bool should_log() noexcept;
578
579 template <Level LevelT>
580 static void finalize_log(std::string_view log_view);
581
582 template <typename DetailT>
583 static void push_detail_to_stream(DetailT&& detail, FastStream& stream) noexcept;
584
585 template <typename DetailT>
586 static std::string_view format_with_detail(DetailT&& detail, const char* msg, int len) noexcept;
587
588 static char* get_local_buffer() noexcept;
589
590 static FastStream& get_local_stream() noexcept;
591
592 void write_to_console(Level level, std::string_view log) noexcept;
593
594 void write_to_file(Level level, std::string_view log) noexcept;
595
596 std::unique_ptr<struct LoggerImpl> impl_;
597
598 template <Logger::Level LevelT>
599 friend class WrapperStream;
600
602
604};
605
606////////////////////////////////////////////////////////////////
607/// Details
608////////////////////////////////////////////////////////////////
609
610inline constexpr std::string_view Logger::extract_filename(std::string_view path) noexcept {
611 auto pos = path.find_last_of("/\\");
612 return (pos == std::string_view::npos) ? path : path.substr(pos + 1);
613}
614
615template <Logger::Level LevelT, typename DetailT, typename... ArgsT>
616inline void Logger::print_stream_style([[maybe_unused]] DetailT&& detail, [[maybe_unused]] ArgsT&&... args) {
617 if (!should_log<LevelT>()) {
618 return;
619 }
620
621 auto& stream = get_local_stream();
622
623 if constexpr (std::is_same_v<std::decay_t<DetailT>, DetailInfo>) {
624 push_detail_to_stream(detail, stream);
625 }
626
627 (void)(stream << ... << args);
628
629 finalize_log<LevelT>(stream.take_view());
630}
631
632template <Logger::Level LevelT, typename DetailT, typename... ArgsT>
633inline void Logger::print_format_style([[maybe_unused]] DetailT&& detail,
635 [[maybe_unused]] ArgsT&&... args) {
636 if (!should_log<LevelT>()) {
637 return;
638 }
639
640 std::string_view log_view;
641
642 auto* local_buffer = get_local_buffer();
643 auto result = format::format_to_n(local_buffer, kLocalBufferSize - 1, format, std::forward<ArgsT>(args)...);
644 auto written = static_cast<int>(result.out - local_buffer);
645
646 local_buffer[written] = '\0';
647
648 log_view = format_with_detail(detail, local_buffer, written);
649
650 finalize_log<LevelT>(log_view);
651}
652
653template <Logger::Level LevelT, typename DetailT, typename FormatT, typename... ArgsT>
654inline void Logger::print_c_style([[maybe_unused]] DetailT&& detail, [[maybe_unused]] FormatT&& format,
655 [[maybe_unused]] ArgsT&&... args) {
656 if (!should_log<LevelT>()) {
657 return;
658 }
659
660 std::string_view log_view;
661
662 if constexpr (sizeof...(ArgsT) == 0) {
663 // static_assert(Traits::ExpectFalse<DetailT>(), "VLINK_CLOG_* Format error.");
664
665 auto& stream = get_local_stream();
666
667 if constexpr (std::is_same_v<std::decay_t<DetailT>, DetailInfo>) {
668 push_detail_to_stream(detail, stream);
669 }
670
671 stream << format;
672 log_view = stream.take_view();
673 } else {
674 auto* local_buffer = get_local_buffer();
675 auto written = std::snprintf(local_buffer, kLocalBufferSize - 1, format, args...);
676
677 if VUNLIKELY (written < 0) {
678 written = 0;
679 } else if VUNLIKELY (written > kLocalBufferSize - 1) {
680 written = kLocalBufferSize - 1;
681 }
682
683 log_view = format_with_detail(detail, local_buffer, written);
684 }
685
686 finalize_log<LevelT>(log_view);
687}
688
689template <Logger::Level LevelT, typename... ArgsT>
690inline void Logger::print([[maybe_unused]] ArgsT&&... args) {
692}
693
694template <Logger::Level LevelT>
695inline bool Logger::should_log() noexcept {
696 if constexpr (LevelT < Logger::kMinimumLevel || LevelT >= Logger::kOff) {
697 return false;
698 } else if constexpr (LevelT == Logger::kFatal) {
699 return true;
700 } else {
701 return Logger::is_writable(LevelT);
702 }
703}
704
705template <Logger::Level LevelT>
706inline void Logger::finalize_log(std::string_view log_view) {
707 Logger& instance = Logger::get();
708
709 instance.write_to_console(LevelT, log_view);
710 instance.write_to_file(LevelT, log_view);
711
712 if constexpr (LevelT == Logger::kFatal) {
713 Logger::flush();
714 throw Exception::RuntimeError(std::string(log_view));
715 }
716}
717
718template <typename DetailT>
719inline void Logger::push_detail_to_stream(DetailT&& detail, FastStream& stream) noexcept {
720 auto& [file, line] = detail;
721 stream << "{" << file << ":" << line << "} ";
722}
723
724template <typename DetailT>
725inline std::string_view Logger::format_with_detail(DetailT&& detail, const char* msg, int len) noexcept {
726 if constexpr (std::is_same_v<std::decay_t<DetailT>, Logger::DetailInfo>) {
727 auto& stream = Logger::get_local_stream();
728
729 push_detail_to_stream(detail, stream);
730
731 if VLIKELY (len > 0) {
732 stream.write_raw(msg, static_cast<size_t>(len));
733 }
734
735 return stream.take_view();
736 } else {
737 if VLIKELY (len > 0) {
738 return std::string_view(msg, static_cast<size_t>(len));
739 }
740
741 return {};
742 }
743}
744
745} // namespace vlink
746
748
749////////////////////////////////////////////////////////////////
750/// Macro Definitions
751////////////////////////////////////////////////////////////////
752
753#define VLINK_LOG_GET_DETAIL(level) \
754 ([]() -> auto { \
755 if constexpr ((level) >= VLinkLogger::kDetailLevel) { \
756 return VLinkLogger::DetailInfo{VLinkLogger::extract_filename(__FILE__), __LINE__}; \
757 } else { \
758 return VLinkLogger::NoDetail{}; \
759 } \
760 })()
761
762#define VLINK_LOG_HEX(offset) std::hex, std::uppercase, std::setw(offset), std::setfill('0')
763
764#define VLINK_LOG_HEXSS(offset) std::hex << std::uppercase << std::setw(offset) << std::setfill('0')
765
766#define VLINK_LOG_IF_T VLinkLogger::is_writable(VLinkLogger::kTrace)
767
768#define VLINK_LOG_IF_D VLinkLogger::is_writable(VLinkLogger::kDebug)
769
770#define VLINK_LOG_IF_I VLinkLogger::is_writable(VLinkLogger::kInfo)
771
772#define VLINK_LOG_IF_W VLinkLogger::is_writable(VLinkLogger::kWarn)
773
774#define VLINK_LOG_IF_E VLinkLogger::is_writable(VLinkLogger::kError)
775
776#define VLINK_LOG_IF_F VLinkLogger::is_writable(VLinkLogger::kFatal)
777
778#define VLINK_LOG_T(...) \
779 VLinkLogger::print_stream_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
780
781#define VLINK_LOG_D(...) \
782 VLinkLogger::print_stream_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
783
784#define VLINK_LOG_I(...) \
785 VLinkLogger::print_stream_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
786
787#define VLINK_LOG_W(...) \
788 VLinkLogger::print_stream_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
789
790#define VLINK_LOG_E(...) \
791 VLinkLogger::print_stream_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
792
793#define VLINK_LOG_F(...) \
794 VLinkLogger::print_stream_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
795
796#define VLINK_MLOG_T(...) \
797 VLinkLogger::print_format_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
798
799#define VLINK_MLOG_D(...) \
800 VLinkLogger::print_format_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
801
802#define VLINK_MLOG_I(...) \
803 VLinkLogger::print_format_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
804
805#define VLINK_MLOG_W(...) \
806 VLinkLogger::print_format_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
807
808#define VLINK_MLOG_E(...) \
809 VLinkLogger::print_format_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
810
811#define VLINK_MLOG_F(...) \
812 VLinkLogger::print_format_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
813
814#define VLINK_CLOG_T(...) \
815 VLinkLogger::print_c_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
816
817#define VLINK_CLOG_D(...) \
818 VLinkLogger::print_c_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
819
820#define VLINK_CLOG_I(...) \
821 VLinkLogger::print_c_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
822
823#define VLINK_CLOG_W(...) \
824 VLinkLogger::print_c_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
825
826#define VLINK_CLOG_E(...) \
827 VLinkLogger::print_c_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
828
829#define VLINK_CLOG_F(...) \
830 VLinkLogger::print_c_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
831
832#define VLINK_SLOG_T VLinkLogger::WrapperStream<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace))
833
834#define VLINK_SLOG_D VLinkLogger::WrapperStream<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug))
835
836#define VLINK_SLOG_I VLinkLogger::WrapperStream<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo))
837
838#define VLINK_SLOG_W VLinkLogger::WrapperStream<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn))
839
840#define VLINK_SLOG_E VLinkLogger::WrapperStream<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError))
841
842#define VLINK_SLOG_F VLinkLogger::WrapperStream<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal))
843
844#ifndef VLINK_LOG_DISABLE_SHORT
845
846#define VLOG_T(...) VLINK_LOG_T(__VA_ARGS__)
847
848#define VLOG_D(...) VLINK_LOG_D(__VA_ARGS__)
849
850#define VLOG_I(...) VLINK_LOG_I(__VA_ARGS__)
851
852#define VLOG_W(...) VLINK_LOG_W(__VA_ARGS__)
853
854#define VLOG_E(...) VLINK_LOG_E(__VA_ARGS__)
855
856#define VLOG_F(...) VLINK_LOG_F(__VA_ARGS__)
857
858#define CLOG_T(...) VLINK_CLOG_T(__VA_ARGS__)
859
860#define CLOG_D(...) VLINK_CLOG_D(__VA_ARGS__)
861
862#define CLOG_I(...) VLINK_CLOG_I(__VA_ARGS__)
863
864#define CLOG_W(...) VLINK_CLOG_W(__VA_ARGS__)
865
866#define CLOG_E(...) VLINK_CLOG_E(__VA_ARGS__)
867
868#define CLOG_F(...) VLINK_CLOG_F(__VA_ARGS__)
869
870#define MLOG_T(...) VLINK_MLOG_T(__VA_ARGS__)
871
872#define MLOG_D(...) VLINK_MLOG_D(__VA_ARGS__)
873
874#define MLOG_I(...) VLINK_MLOG_I(__VA_ARGS__)
875
876#define MLOG_W(...) VLINK_MLOG_W(__VA_ARGS__)
877
878#define MLOG_E(...) VLINK_MLOG_E(__VA_ARGS__)
879
880#define MLOG_F(...) VLINK_MLOG_F(__VA_ARGS__)
881
882#define SLOG_T VLINK_SLOG_T
883
884#define SLOG_D VLINK_SLOG_D
885
886#define SLOG_I VLINK_SLOG_I
887
888#define SLOG_W VLINK_SLOG_W
889
890#define SLOG_E VLINK_SLOG_E
891
892#define SLOG_F VLINK_SLOG_F
893
894#endif
VLink-specific exception types wrapping the C++ standard exception hierarchy.
A high-performance std::ostream backed by a resizable std::string buffer.
Lightweight header-only {} placeholder formatter with no dynamic allocation.
vlink::Logger VLinkLogger
定义 logger.h:747
Platform-independent macro definitions for the VLink library.
#define VUNLIKELY(...)
Shorthand alias for VLINK_UNLIKELY. Hints that the expression is unlikely true.
定义 macros.h:302
#define VLINK_SINGLETON_CHECK(classname)
Injects a compile-time and run-time singleton enforcement guard.
定义 macros.h:203
#define VLINK_EXPORT
定义 macros.h:85
#define VLIKELY(...)
Shorthand alias for VLINK_LIKELY. Hints that the expression is likely true.
定义 macros.h:297
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
定义 macros.h:184
STL namespace