102 #include <string_view>
103 #include <type_traits>
161 #ifdef VLINK_LOG_LEVEL
162 static constexpr uint8_t kMinimumLevel = VLINK_LOG_LEVEL;
164 static constexpr uint8_t kMinimumLevel = kTrace;
174 #ifdef VLINK_LOG_DETAIL_LEVEL
175 static constexpr uint8_t kDetailLevel = VLINK_LOG_DETAIL_LEVEL;
177 static constexpr uint8_t kDetailLevel = kWarn;
186 static constexpr
int kLocalBufferSize = 4096;
224 static void init(
const std::string& app_name =
"",
const std::string& log_path =
"") noexcept;
240 static
void flush() noexcept;
247 static
void register_console_handler(
Callback&& callback) noexcept;
254 static
void register_file_handler(
Callback&& callback) noexcept;
261 static
void set_console_level(
Level level) noexcept;
268 static
void set_file_level(
Level level) noexcept;
275 static
void set_console_fmt_enable(
bool enable) noexcept;
282 [[nodiscard]] static
Level get_console_level() noexcept;
289 [[nodiscard]] static
Level get_file_level() noexcept;
296 [[nodiscard]] static
bool get_console_fmt_enable() noexcept;
303 static
void set_stream_flag(std::ios_base::fmtflags flags) noexcept;
310 static
void set_stream_precision(
int precision) noexcept;
317 static
void set_stream_width(
int width) noexcept;
324 [[nodiscard]] static std::ios_base::fmtflags get_stream_flag() noexcept;
331 [[nodiscard]] static
int get_stream_precision() noexcept;
338 [[nodiscard]] static
int get_stream_width() noexcept;
345 static
void enable_backtrace(
size_t size) noexcept;
350 static
void disable_backtrace() noexcept;
355 static
void dump_backtrace() noexcept;
362 [[nodiscard]] static
bool is_busy() noexcept;
373 [[nodiscard]] static
bool is_writable(
Level level) noexcept;
381 [[nodiscard]] static constexpr std::string_view extract_filename(std::string_view path) noexcept;
396 template <
Level LevelT, typename DetailT, typename... ArgsT>
397 static
void print_stream_style(DetailT&& detail, ArgsT&&... args);
409 template <
Level LevelT, typename DetailT, typename... ArgsT>
410 static
void print_format_style(DetailT&& detail, format::
format_string<ArgsT...> format, ArgsT&&... args);
423 template <
Logger::
Level LevelT, typename DetailT, typename FormatT, typename... ArgsT>
424 static
void print_c_style(DetailT&& detail, FormatT&& format, ArgsT&&... args);
433 template <
Level LevelT, typename... ArgsT>
434 static
void print(ArgsT&&... args);
452 static constexpr
bool kIsEnabled = (LevelT >= kMinimumLevel && LevelT <
Logger::kOff);
455 if constexpr (kIsEnabled) {
456 if (should_log<LevelT>()) {
458 stream_ = &Logger::get_local_stream();
464 if constexpr (kIsEnabled) {
465 if (should_log<LevelT>()) {
467 stream_ = &Logger::get_local_stream();
469 push_detail_to_stream(detail, *stream_);
475 other.stream_ =
nullptr;
476 other.enabled_ =
false;
482 if constexpr (kIsEnabled) {
484 finalize_log<LevelT>(stream_->take_view());
489 template <
typename T>
491 if constexpr (kIsEnabled) {
493 *stream_ << std::forward<T>(t);
504 bool enabled_{
false};
512 template <Level LevelT>
513 static
bool should_log() noexcept;
515 template <Level LevelT>
516 static
void finalize_log(std::string_view log_view);
518 template <typename DetailT>
519 static
void push_detail_to_stream(DetailT&& detail, FastStream& stream) noexcept;
521 template <typename DetailT>
522 static std::string_view format_with_detail(DetailT&& detail, const
char* msg,
int len) noexcept;
524 static
char* get_local_buffer() noexcept;
526 static FastStream& get_local_stream() noexcept;
528 void write_to_console(Level level, std::string_view log) noexcept;
530 void write_to_file(Level level, std::string_view log) noexcept;
533 std::unique_ptr<Impl> impl_;
535 template <Logger::Level LevelT>
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);
552 template <
Logger::Level LevelT,
typename DetailT,
typename... ArgsT>
554 if (!should_log<LevelT>()) {
558 auto& stream = get_local_stream();
560 if constexpr (std::is_same_v<std::decay_t<DetailT>,
DetailInfo>) {
561 push_detail_to_stream(detail, stream);
564 (void)(stream << ... << args);
566 finalize_log<LevelT>(stream.take_view());
569 template <
Logger::Level LevelT,
typename DetailT,
typename... ArgsT>
572 [[maybe_unused]] ArgsT&&... args) {
573 if (!should_log<LevelT>()) {
577 std::string_view log_view;
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);
583 local_buffer[written] =
'\0';
585 log_view = format_with_detail(detail, local_buffer, written);
587 finalize_log<LevelT>(log_view);
590 template <
Logger::Level LevelT,
typename DetailT,
typename FormatT,
typename... ArgsT>
592 [[maybe_unused]] ArgsT&&... args) {
593 if (!should_log<LevelT>()) {
597 std::string_view log_view;
599 if constexpr (
sizeof...(ArgsT) == 0) {
600 auto& stream = get_local_stream();
602 if constexpr (std::is_same_v<std::decay_t<DetailT>,
DetailInfo>) {
603 push_detail_to_stream(detail, stream);
607 log_view = stream.take_view();
609 auto* local_buffer = get_local_buffer();
610 auto written = std::snprintf(local_buffer, kLocalBufferSize - 1, format, args...);
614 }
else if VUNLIKELY (written > kLocalBufferSize - 1) {
615 written = kLocalBufferSize - 1;
618 log_view = format_with_detail(detail, local_buffer, written);
621 finalize_log<LevelT>(log_view);
626 print_stream_style<LevelT>(
NoDetail{}, args...);
629 template <Logger::Level LevelT>
630 inline bool Logger::should_log() noexcept {
631 if constexpr (LevelT < Logger::kMinimumLevel || LevelT >=
Logger::kOff) {
640 template <Logger::Level LevelT>
641 inline void Logger::finalize_log(std::string_view log_view) {
644 instance.write_to_console(LevelT, log_view);
645 instance.write_to_file(LevelT, log_view);
649 throw Exception::RuntimeError(std::string(log_view));
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 <<
"} ";
659 template <
typename DetailT>
660 inline std::string_view Logger::format_with_detail(DetailT&& detail,
const char* msg,
int len) noexcept {
662 auto& stream = Logger::get_local_stream();
664 push_detail_to_stream(detail, stream);
667 stream.write_raw(msg,
static_cast<size_t>(len));
670 return stream.take_view();
673 return std::string_view(msg,
static_cast<size_t>(len));
688 #define VLINK_LOG_GET_DETAIL(level) \
690 if constexpr ((level) >= VLinkLogger::kDetailLevel) { \
691 return VLinkLogger::DetailInfo{VLinkLogger::extract_filename(__FILE__), __LINE__}; \
693 return VLinkLogger::NoDetail{}; \
697 #define VLINK_LOG_HEX(offset) std::hex, std::uppercase, std::setw(offset), std::setfill('0')
699 #define VLINK_LOG_HEXSS(offset) std::hex << std::uppercase << std::setw(offset) << std::setfill('0')
701 #define VLINK_LOG_IF_T VLinkLogger::is_writable(VLinkLogger::kTrace)
703 #define VLINK_LOG_IF_D VLinkLogger::is_writable(VLinkLogger::kDebug)
705 #define VLINK_LOG_IF_I VLinkLogger::is_writable(VLinkLogger::kInfo)
707 #define VLINK_LOG_IF_W VLinkLogger::is_writable(VLinkLogger::kWarn)
709 #define VLINK_LOG_IF_E VLinkLogger::is_writable(VLinkLogger::kError)
711 #define VLINK_LOG_IF_F VLinkLogger::is_writable(VLinkLogger::kFatal)
713 #define VLINK_LOG_T(...) \
714 VLinkLogger::print_stream_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
716 #define VLINK_LOG_D(...) \
717 VLinkLogger::print_stream_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
719 #define VLINK_LOG_I(...) \
720 VLinkLogger::print_stream_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
722 #define VLINK_LOG_W(...) \
723 VLinkLogger::print_stream_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
725 #define VLINK_LOG_E(...) \
726 VLinkLogger::print_stream_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
728 #define VLINK_LOG_F(...) \
729 VLinkLogger::print_stream_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
731 #define VLINK_MLOG_T(...) \
732 VLinkLogger::print_format_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
734 #define VLINK_MLOG_D(...) \
735 VLinkLogger::print_format_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
737 #define VLINK_MLOG_I(...) \
738 VLinkLogger::print_format_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
740 #define VLINK_MLOG_W(...) \
741 VLinkLogger::print_format_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
743 #define VLINK_MLOG_E(...) \
744 VLinkLogger::print_format_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
746 #define VLINK_MLOG_F(...) \
747 VLinkLogger::print_format_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
749 #define VLINK_CLOG_T(...) \
750 VLinkLogger::print_c_style<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace), __VA_ARGS__)
752 #define VLINK_CLOG_D(...) \
753 VLinkLogger::print_c_style<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug), __VA_ARGS__)
755 #define VLINK_CLOG_I(...) \
756 VLinkLogger::print_c_style<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo), __VA_ARGS__)
758 #define VLINK_CLOG_W(...) \
759 VLinkLogger::print_c_style<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn), __VA_ARGS__)
761 #define VLINK_CLOG_E(...) \
762 VLinkLogger::print_c_style<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError), __VA_ARGS__)
764 #define VLINK_CLOG_F(...) \
765 VLinkLogger::print_c_style<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal), __VA_ARGS__)
767 #define VLINK_SLOG_T VLinkLogger::WrapperStream<VLinkLogger::kTrace>(VLINK_LOG_GET_DETAIL(VLinkLogger::kTrace))
769 #define VLINK_SLOG_D VLinkLogger::WrapperStream<VLinkLogger::kDebug>(VLINK_LOG_GET_DETAIL(VLinkLogger::kDebug))
771 #define VLINK_SLOG_I VLinkLogger::WrapperStream<VLinkLogger::kInfo>(VLINK_LOG_GET_DETAIL(VLinkLogger::kInfo))
773 #define VLINK_SLOG_W VLinkLogger::WrapperStream<VLinkLogger::kWarn>(VLINK_LOG_GET_DETAIL(VLinkLogger::kWarn))
775 #define VLINK_SLOG_E VLinkLogger::WrapperStream<VLinkLogger::kError>(VLINK_LOG_GET_DETAIL(VLinkLogger::kError))
777 #define VLINK_SLOG_F VLinkLogger::WrapperStream<VLinkLogger::kFatal>(VLINK_LOG_GET_DETAIL(VLinkLogger::kFatal))
779 #ifndef VLINK_LOG_DISABLE_SHORT
781 #define VLOG_T(...) VLINK_LOG_T(__VA_ARGS__)
783 #define VLOG_D(...) VLINK_LOG_D(__VA_ARGS__)
785 #define VLOG_I(...) VLINK_LOG_I(__VA_ARGS__)
787 #define VLOG_W(...) VLINK_LOG_W(__VA_ARGS__)
789 #define VLOG_E(...) VLINK_LOG_E(__VA_ARGS__)
791 #define VLOG_F(...) VLINK_LOG_F(__VA_ARGS__)
793 #define CLOG_T(...) VLINK_CLOG_T(__VA_ARGS__)
795 #define CLOG_D(...) VLINK_CLOG_D(__VA_ARGS__)
797 #define CLOG_I(...) VLINK_CLOG_I(__VA_ARGS__)
799 #define CLOG_W(...) VLINK_CLOG_W(__VA_ARGS__)
801 #define CLOG_E(...) VLINK_CLOG_E(__VA_ARGS__)
803 #define CLOG_F(...) VLINK_CLOG_F(__VA_ARGS__)
805 #define MLOG_T(...) VLINK_MLOG_T(__VA_ARGS__)
807 #define MLOG_D(...) VLINK_MLOG_D(__VA_ARGS__)
809 #define MLOG_I(...) VLINK_MLOG_I(__VA_ARGS__)
811 #define MLOG_W(...) VLINK_MLOG_W(__VA_ARGS__)
813 #define MLOG_E(...) VLINK_MLOG_E(__VA_ARGS__)
815 #define MLOG_F(...) VLINK_MLOG_F(__VA_ARGS__)
817 #define SLOG_T VLINK_SLOG_T
819 #define SLOG_D VLINK_SLOG_D
821 #define SLOG_I VLINK_SLOG_I
823 #define SLOG_W VLINK_SLOG_W
825 #define SLOG_E VLINK_SLOG_E
827 #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:447
WrapperStream & operator<<(T &&t) noexcept
Definition: logger.h:490
~WrapperStream() noexcept(LevelT !=Level::kFatal)
Definition: logger.h:481
WrapperStream(WrapperStream &&other) noexcept
Definition: logger.h:474
WrapperStream(Logger::NoDetail) noexcept
Definition: logger.h:454
WrapperStream(DetailInfo &&detail) noexcept
Definition: logger.h:463
WrapperStream & operator=(WrapperStream &&)=delete
Global singleton logger with four formatting styles and independently configurable sinks.
Definition: logger.h:124
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:144
@ kOff
Disable sink.
Definition: logger.h:151
@ kFatal
Unrecoverable; throws Exception::RuntimeError.
Definition: logger.h:150
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:132
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:204
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:134
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:212