111 #include <string_view>
112 #include <type_traits>
170 #ifdef VLINK_LOG_LEVEL
171 static constexpr uint8_t kMinimumLevel = VLINK_LOG_LEVEL;
173 static constexpr uint8_t kMinimumLevel = kTrace;
183 #ifdef VLINK_LOG_DETAIL_LEVEL
184 static constexpr uint8_t kDetailLevel = VLINK_LOG_DETAIL_LEVEL;
186 static constexpr uint8_t kDetailLevel = kWarn;
195 static constexpr
int kLocalBufferSize = 4096;
233 static void init(
const std::string& app_name =
"",
const std::string& log_path =
"") noexcept;
249 static
void flush() noexcept;
256 static
void register_console_handler(
Callback&& callback) noexcept;
263 static
void register_file_handler(
Callback&& callback) noexcept;
270 static
void set_console_level(
Level level) noexcept;
277 static
void set_file_level(
Level level) noexcept;
284 static
void set_console_fmt_enable(
bool enable) noexcept;
291 [[nodiscard]] static
Level get_console_level() noexcept;
298 [[nodiscard]] static
Level get_file_level() noexcept;
305 [[nodiscard]] static
bool get_console_fmt_enable() noexcept;
312 static
void set_stream_flag(std::ios_base::fmtflags flags) noexcept;
319 static
void set_stream_precision(
int precision) noexcept;
326 static
void set_stream_width(
int width) noexcept;
333 [[nodiscard]] static std::ios_base::fmtflags get_stream_flag() noexcept;
340 [[nodiscard]] static
int get_stream_precision() noexcept;
347 [[nodiscard]] static
int get_stream_width() noexcept;
354 static
void enable_backtrace(
size_t size) noexcept;
359 static
void disable_backtrace() noexcept;
364 static
void dump_backtrace() noexcept;
371 [[nodiscard]] static
bool is_busy() noexcept;
382 [[nodiscard]] static
bool is_writable(
Level level) noexcept;
392 [[nodiscard]] static
bool try_acquire_periodic_log(
Level level, int64_t interval_ms,
393 std::atomic<uint64_t>& last_log_time_ns) noexcept;
401 [[nodiscard]] static constexpr std::string_view extract_filename(std::string_view path) noexcept;
416 template <
Level LevelT, typename DetailT, typename... ArgsT>
417 static
void print_stream_style(DetailT&& detail, ArgsT&&... args);
429 template <
Level LevelT, typename DetailT, typename... ArgsT>
430 static
void print_format_style(DetailT&& detail, format::
format_string<ArgsT...> format, ArgsT&&... args);
443 template <
Logger::
Level LevelT, typename DetailT, typename FormatT, typename... ArgsT>
444 static
void print_c_style(DetailT&& detail, FormatT&& format, ArgsT&&... args);
453 template <
Level LevelT, typename... ArgsT>
454 static
void print(ArgsT&&... args);
472 static constexpr
bool kIsEnabled = (LevelT >= kMinimumLevel && LevelT <
Logger::kOff);
475 if constexpr (kIsEnabled) {
476 if (should_log<LevelT>()) {
478 stream_ = &Logger::get_local_stream();
484 if constexpr (kIsEnabled) {
485 if (should_log<LevelT>()) {
487 stream_ = &Logger::get_local_stream();
489 push_detail_to_stream(detail, *stream_);
495 other.stream_ =
nullptr;
496 other.enabled_ =
false;
502 if constexpr (kIsEnabled) {
504 finalize_log<LevelT>(stream_->take_view());
509 template <
typename T>
511 if constexpr (kIsEnabled) {
513 *stream_ << std::forward<T>(t);
524 bool enabled_{
false};
532 template <Level LevelT>
533 static
bool should_log() noexcept;
535 template <Level LevelT>
536 static
void finalize_log(std::string_view log_view);
538 template <typename DetailT>
539 static
void push_detail_to_stream(DetailT&& detail, FastStream& stream) noexcept;
541 template <typename DetailT>
542 static std::string_view format_with_detail(DetailT&& detail, const
char* msg,
int len) noexcept;
544 static
char* get_local_buffer() noexcept;
546 static FastStream& get_local_stream() noexcept;
548 void write_to_console(Level level, std::string_view log) noexcept;
550 void write_to_file(Level level, std::string_view log) noexcept;
553 std::unique_ptr<Impl> impl_;
555 template <Logger::Level LevelT>
567 inline constexpr std::string_view
Logger::extract_filename(std::string_view path) noexcept {
568 auto pos = path.find_last_of(
"/\\");
569 return (pos == std::string_view::npos) ? path : path.substr(pos + 1);
572 template <
Logger::Level LevelT,
typename DetailT,
typename... ArgsT>
574 if (!should_log<LevelT>()) {
578 auto& stream = get_local_stream();
580 if constexpr (std::is_same_v<std::decay_t<DetailT>,
DetailInfo>) {
581 push_detail_to_stream(detail, stream);
584 (void)(stream << ... << args);
586 finalize_log<LevelT>(stream.take_view());
589 template <
Logger::Level LevelT,
typename DetailT,
typename... ArgsT>
592 [[maybe_unused]] ArgsT&&... args) {
593 if (!should_log<LevelT>()) {
597 std::string_view log_view;
599 auto* local_buffer = get_local_buffer();
600 auto result =
format::format_to_n(local_buffer, kLocalBufferSize - 1, format, std::forward<ArgsT>(args)...);
601 auto written =
static_cast<int>(result.out - local_buffer);
603 local_buffer[written] =
'\0';
605 log_view = format_with_detail(detail, local_buffer, written);
607 finalize_log<LevelT>(log_view);
610 template <
Logger::Level LevelT,
typename DetailT,
typename FormatT,
typename... ArgsT>
612 [[maybe_unused]] ArgsT&&... args) {
613 if (!should_log<LevelT>()) {
617 std::string_view log_view;
619 if constexpr (
sizeof...(ArgsT) == 0) {
620 auto& stream = get_local_stream();
622 if constexpr (std::is_same_v<std::decay_t<DetailT>,
DetailInfo>) {
623 push_detail_to_stream(detail, stream);
627 log_view = stream.take_view();
629 auto* local_buffer = get_local_buffer();
630 auto written = std::snprintf(local_buffer, kLocalBufferSize - 1, format, args...);
634 }
else if VUNLIKELY (written > kLocalBufferSize - 1) {
635 written = kLocalBufferSize - 1;
638 log_view = format_with_detail(detail, local_buffer, written);
641 finalize_log<LevelT>(log_view);
646 print_stream_style<LevelT>(
NoDetail{}, args...);
649 template <Logger::Level LevelT>
650 inline bool Logger::should_log() noexcept {
651 if constexpr (LevelT < Logger::kMinimumLevel || LevelT >=
Logger::kOff) {
660 template <Logger::Level LevelT>
661 inline void Logger::finalize_log(std::string_view log_view) {
664 instance.write_to_console(LevelT, log_view);
665 instance.write_to_file(LevelT, log_view);
669 throw Exception::RuntimeError(std::string(log_view));
673 template <
typename DetailT>
674 inline void Logger::push_detail_to_stream(DetailT&& detail, FastStream& stream) noexcept {
675 auto& [file, line] = detail;
676 stream <<
"{" << file <<
":" << line <<
"} ";
679 template <
typename DetailT>
680 inline std::string_view Logger::format_with_detail(DetailT&& detail,
const char* msg,
int len) noexcept {
682 auto& stream = Logger::get_local_stream();
684 push_detail_to_stream(detail, stream);
687 stream.write_raw(msg,
static_cast<size_t>(len));
690 return stream.take_view();
693 return std::string_view(msg,
static_cast<size_t>(len));
708 #define VLINK_LOG_GET_DETAIL(level) \
710 if constexpr ((level) >= VLinkLogger::kDetailLevel) { \
711 return VLinkLogger::DetailInfo{VLinkLogger::extract_filename(__FILE__), __LINE__}; \
713 return VLinkLogger::NoDetail{}; \
717 #define VLINK_LOG_HEX(offset) std::hex, std::uppercase, std::setw(offset), std::setfill('0')
719 #define VLINK_LOG_HEXSS(offset) std::hex << std::uppercase << std::setw(offset) << std::setfill('0')
721 #define VLINK_LOG_IF_T VLinkLogger::is_writable(VLinkLogger::kTrace)
723 #define VLINK_LOG_IF_D VLinkLogger::is_writable(VLinkLogger::kDebug)
725 #define VLINK_LOG_IF_I VLinkLogger::is_writable(VLinkLogger::kInfo)
727 #define VLINK_LOG_IF_W VLinkLogger::is_writable(VLinkLogger::kWarn)
729 #define VLINK_LOG_IF_E VLinkLogger::is_writable(VLinkLogger::kError)
731 #define VLINK_LOG_IF_F VLinkLogger::is_writable(VLinkLogger::kFatal)
733 #define VLINK_LOG_T(...) \
734 VLinkLogger::print_stream_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
736 #define VLINK_LOG_D(...) \
737 VLinkLogger::print_stream_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
739 #define VLINK_LOG_I(...) \
740 VLinkLogger::print_stream_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
742 #define VLINK_LOG_W(...) \
743 VLinkLogger::print_stream_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
745 #define VLINK_LOG_E(...) \
746 VLinkLogger::print_stream_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
748 #define VLINK_LOG_F(...) \
749 VLinkLogger::print_stream_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
751 #define VLINK_MLOG_T(...) \
752 VLinkLogger::print_format_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
754 #define VLINK_MLOG_D(...) \
755 VLinkLogger::print_format_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
757 #define VLINK_MLOG_I(...) \
758 VLinkLogger::print_format_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
760 #define VLINK_MLOG_W(...) \
761 VLinkLogger::print_format_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
763 #define VLINK_MLOG_E(...) \
764 VLinkLogger::print_format_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
766 #define VLINK_MLOG_F(...) \
767 VLinkLogger::print_format_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
769 #define VLINK_CLOG_T(...) \
770 VLinkLogger::print_c_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
772 #define VLINK_CLOG_D(...) \
773 VLinkLogger::print_c_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
775 #define VLINK_CLOG_I(...) \
776 VLinkLogger::print_c_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
778 #define VLINK_CLOG_W(...) \
779 VLinkLogger::print_c_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
781 #define VLINK_CLOG_E(...) \
782 VLinkLogger::print_c_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
784 #define VLINK_CLOG_F(...) \
785 VLinkLogger::print_c_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
787 #define VLINK_SLOG_T VLinkLogger::WrapperStream<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace))
789 #define VLINK_SLOG_D VLinkLogger::WrapperStream<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug))
791 #define VLINK_SLOG_I VLinkLogger::WrapperStream<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo))
793 #define VLINK_SLOG_W VLinkLogger::WrapperStream<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn))
795 #define VLINK_SLOG_E VLinkLogger::WrapperStream<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError))
797 #define VLINK_SLOG_F VLinkLogger::WrapperStream<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal))
799 #define VLINK_LOG_EVERY_MS_IMPL(level, interval_ms, ...) \
801 if constexpr ((level) >= VLinkLogger::kMinimumLevel && (level) < VLinkLogger::kFatal) { \
802 if VUNLIKELY ([](int64_t vlink_interval_ms) noexcept { \
803 static std::atomic<uint64_t> vlink_last_log_time_ns{0}; \
804 return VLinkLogger::try_acquire_periodic_log(level, vlink_interval_ms, vlink_last_log_time_ns); \
805 }(static_cast<int64_t>(interval_ms))) { \
806 VLinkLogger::print_stream_style<level>(VLINK_LOG_GET_DETAIL(level), __VA_ARGS__); \
811 #define VLINK_LOG_T_EVERY_MS(interval_ms, ...) VLINK_LOG_EVERY_MS_IMPL(VLinkLogger::kTrace, interval_ms, __VA_ARGS__)
813 #define VLINK_LOG_D_EVERY_MS(interval_ms, ...) VLINK_LOG_EVERY_MS_IMPL(VLinkLogger::kDebug, interval_ms, __VA_ARGS__)
815 #define VLINK_LOG_I_EVERY_MS(interval_ms, ...) VLINK_LOG_EVERY_MS_IMPL(VLinkLogger::kInfo, interval_ms, __VA_ARGS__)
817 #define VLINK_LOG_W_EVERY_MS(interval_ms, ...) VLINK_LOG_EVERY_MS_IMPL(VLinkLogger::kWarn, interval_ms, __VA_ARGS__)
819 #define VLINK_LOG_E_EVERY_MS(interval_ms, ...) VLINK_LOG_EVERY_MS_IMPL(VLinkLogger::kError, interval_ms, __VA_ARGS__)
821 #ifndef VLINK_LOG_DISABLE_SHORT
823 #define VLOG_T_EVERY_MS(interval_ms, ...) VLINK_LOG_T_EVERY_MS(interval_ms, __VA_ARGS__)
825 #define VLOG_D_EVERY_MS(interval_ms, ...) VLINK_LOG_D_EVERY_MS(interval_ms, __VA_ARGS__)
827 #define VLOG_I_EVERY_MS(interval_ms, ...) VLINK_LOG_I_EVERY_MS(interval_ms, __VA_ARGS__)
829 #define VLOG_W_EVERY_MS(interval_ms, ...) VLINK_LOG_W_EVERY_MS(interval_ms, __VA_ARGS__)
831 #define VLOG_E_EVERY_MS(interval_ms, ...) VLINK_LOG_E_EVERY_MS(interval_ms, __VA_ARGS__)
833 #define VLOG_T(...) VLINK_LOG_T(__VA_ARGS__)
835 #define VLOG_D(...) VLINK_LOG_D(__VA_ARGS__)
837 #define VLOG_I(...) VLINK_LOG_I(__VA_ARGS__)
839 #define VLOG_W(...) VLINK_LOG_W(__VA_ARGS__)
841 #define VLOG_E(...) VLINK_LOG_E(__VA_ARGS__)
843 #define VLOG_F(...) VLINK_LOG_F(__VA_ARGS__)
845 #define CLOG_T(...) VLINK_CLOG_T(__VA_ARGS__)
847 #define CLOG_D(...) VLINK_CLOG_D(__VA_ARGS__)
849 #define CLOG_I(...) VLINK_CLOG_I(__VA_ARGS__)
851 #define CLOG_W(...) VLINK_CLOG_W(__VA_ARGS__)
853 #define CLOG_E(...) VLINK_CLOG_E(__VA_ARGS__)
855 #define CLOG_F(...) VLINK_CLOG_F(__VA_ARGS__)
857 #define MLOG_T(...) VLINK_MLOG_T(__VA_ARGS__)
859 #define MLOG_D(...) VLINK_MLOG_D(__VA_ARGS__)
861 #define MLOG_I(...) VLINK_MLOG_I(__VA_ARGS__)
863 #define MLOG_W(...) VLINK_MLOG_W(__VA_ARGS__)
865 #define MLOG_E(...) VLINK_MLOG_E(__VA_ARGS__)
867 #define MLOG_F(...) VLINK_MLOG_F(__VA_ARGS__)
869 #define SLOG_T VLINK_SLOG_T
871 #define SLOG_D VLINK_SLOG_D
873 #define SLOG_I VLINK_SLOG_I
875 #define SLOG_W VLINK_SLOG_W
877 #define SLOG_E VLINK_SLOG_E
879 #define SLOG_F VLINK_SLOG_F
Logger-friendly std::ostream with a custom growable string buffer.
Definition: fast_stream.h:88
RAII helper backing SLOG_*; collects tokens and flushes on destruction.
Definition: logger.h:467
WrapperStream & operator<<(T &&t) noexcept
Definition: logger.h:510
~WrapperStream() noexcept(LevelT !=Level::kFatal)
Definition: logger.h:501
WrapperStream(WrapperStream &&other) noexcept
Definition: logger.h:494
WrapperStream(Logger::NoDetail) noexcept
Definition: logger.h:474
WrapperStream(DetailInfo &&detail) noexcept
Definition: logger.h:483
WrapperStream & operator=(WrapperStream &&)=delete
Global singleton logger with four formatting styles and independently configurable sinks.
Definition: logger.h:133
static void print_stream_style(DetailT &&detail, ArgsT &&... args)
Stream-style entry point (used by VLOG_* / print).
static void print_format_style(DetailT &&detail, format::format_string< ArgsT... > format, ArgsT &&... args)
Placeholder-style entry point (used by MLOG_*).
static Logger & get() noexcept
Returns the global logger instance.
Level
Message severity level.
Definition: logger.h:153
@ kOff
Disable sink.
Definition: logger.h:160
@ kFatal
Unrecoverable; throws Exception::RuntimeError.
Definition: logger.h:159
static bool is_writable(Level level) noexcept
Reports whether a record at level would currently be emitted.
static void print(ArgsT &&... args)
Convenience stream-style entry point without source location.
Style
Internal output style tag used by the print_* family.
Definition: logger.h:141
static void print_c_style(DetailT &&detail, FormatT &&format, ArgsT &&... args)
printf-style entry point (used by CLOG_*).
static void flush() noexcept
Flushes every active sink.
std::pair< std::string_view, int > DetailInfo
Carries the source file name and line number for the detail prefix.
Definition: logger.h:213
static void init(const std::string &app_name="", const std::string &log_path="") noexcept
Initialises the logger singleton.
Move-only type-erased callable analogue of std::move_only_function with pool spill.
Definition: functional.h:135
Thin final wrappers around the standard exception hierarchy used by VLink.
Allocation-light std::ostream backed by a growable string buffer.
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
constexpr std::string_view get() noexcept
Returns the trimmed compile-time identifier for TypeT.
Definition: name_detector.h:603
Sentinel type indicating no detail prefix is attached.
Definition: logger.h:221