#pragma once #include "journal.hpp" #include #include #include #include #include namespace journal { namespace detail { struct source_location { _NODISCARD static constexpr source_location current(const uint_least32_t _Line_ = __builtin_LINE(), const uint_least32_t _Column_ = __builtin_COLUMN(), const char *const _File_ = __builtin_FILE(), const char *const _Function_ = __builtin_FUNCTION()) noexcept { source_location _Result; _Result._Line = _Line_; _Result._Column = _Column_; _Result._File = _File_; _Result._Function = _Function_; return _Result; } _NODISCARD_CTOR constexpr source_location() noexcept = default; _NODISCARD constexpr uint_least32_t line() const noexcept { return _Line; } _NODISCARD constexpr uint_least32_t column() const noexcept { return _Column; } _NODISCARD constexpr const char *file_name() const noexcept { return _File; } _NODISCARD constexpr const char *function_name() const noexcept { return _Function; } private: uint_least32_t _Line{}; uint_least32_t _Column{}; const char *_File = ""; const char *_Function = ""; }; enum LogVerbosity { Trace, Debug, Info, Warn, Error, }; struct Verbosity { journal::detail::LogVerbosity inner; Verbosity(journal::detail::LogVerbosity &&value) : inner(value) {} Verbosity(const journal::detail::LogVerbosity &value) : inner(value) {} auto operator<=>(const Verbosity &rhs) const -> std::strong_ordering { return static_cast>(inner) <=> static_cast>(rhs.inner); } }; constexpr auto to_string(const LogVerbosity& verbosity) -> std::string; namespace formatter { struct Formatter { virtual auto operator()(const Verbosity &verbosity, const source_location &source) -> std::string = 0; virtual ~Formatter() {} }; } // namespace formatter template inline constexpr auto log(const LogVerbosity &verbosity, const detail::source_location &source, std::string_view fmt, Args... args) -> void { const auto msg = std::vformat(fmt, std::make_format_args(args...)); log_internal(verbosity, source, msg); } auto log_internal(const LogVerbosity &verbosity, const detail::source_location source, const std::string &msg) -> void; } // namespace detail using detail::LogVerbosity; auto init_std_out(const LogVerbosity &min = LogVerbosity::Info) -> void; auto init_std_out_err(const LogVerbosity &min = LogVerbosity::Info) -> void; auto init() -> void; auto init_no_threads() -> void; auto set_formatter(std::unique_ptr &&formatter) -> void; auto add_std_out() -> void; auto add_std_err() -> void; auto add_file(std::string_view file_path, std::ios_base::openmode = std::ios_base::ate, const LogVerbosity &min = LogVerbosity::Trace, const LogVerbosity &max = LogVerbosity::Error) -> void; auto add_sink(std::shared_ptr stream, const LogVerbosity &min = LogVerbosity::Trace, const LogVerbosity &max = LogVerbosity::Error) -> void; template inline constexpr auto ptr(T *p) -> const void * { return reinterpret_cast(p); } /// JOURNAL_NONE: undefines all logs /// JOURNAL_ALL: defines all logs, on by default /// JOURNAL_NOT_ALL: does not define any logs by default even it JOURNAL_ALL is /// defined, off by default #if defined(JOURNAL_ALL) && !defined(JOURNAL_NONE) && !defined(JOURNAL_NOT_ALL) #define JOURNAL_TRACE #define JOURNAL_DEBUG #define JOURNAL_INFO #define JOURNAL_WARN #define JOURNAL_ERROR #endif #if defined(JOURNAL_NONE) #undef JOURNAL_TRACE #undef JOURNAL_DEBUG #undef JOURNAL_INFO #undef JOURNAL_WARN #undef JOURNAL_ERROR #endif #ifdef JOURNAL_TRACE template struct trace { trace(std::string_view fmt, Ts &&...args, const detail::source_location &source = detail::source_location::current()) { detail::log(detail::LogVerbosity::Trace, source, fmt, std::forward(args)...); } }; template trace(std::string_view, Ts &&...) -> trace; #else template inline constexpr auto trace(std::string_view fmt, Args... args) -> void {} #endif #ifdef JOURNAL_DEBUG template struct debug { debug(std::string_view fmt, Ts &&...args, const detail::source_location &source = detail::source_location::current()) { detail::log(detail::LogVerbosity::Debug, source, fmt, std::forward(args)...); } }; template debug(std::string_view, Ts &&...) -> debug; #else template inline constexpr auto debug(std::string_view fmt, Args... args) -> void {} #endif #ifdef JOURNAL_INFO template struct info { info(std::string_view fmt, Ts &&...args, const detail::source_location &source = detail::source_location::current()) { detail::log(detail::LogVerbosity::Info, source, fmt, std::forward(args)...); } }; template info(std::string_view, Ts &&...) -> info; #else template inline constexpr auto info(std::string_view fmt, Args... args) -> void {} #endif #ifdef JOURNAL_WARN template struct warn { warn(std::string_view fmt, Ts &&...args, const detail::source_location &source = detail::source_location::current()) { detail::log(detail::LogVerbosity::Warn, source, fmt, std::forward(args)...); } }; template warn(std::string_view, Ts &&...) -> warn; #else template inline constexpr auto warn(std::string_view fmt, Args... args) -> void {} #endif #ifdef JOURNAL_ERROR template struct error { error(std::string_view fmt, Ts &&...args, const detail::source_location &source = detail::source_location::current()) { detail::log(detail::LogVerbosity::Error, source, fmt, std::forward(args)...); } }; template error(std::string_view, Ts &&...) -> error; #else template inline constexpr auto error(std::string_view fmt, Args... args) -> void {} #endif } // namespace journal /// JOURNAL_GLOG_COMPAT: enables LOG_F macro format which GLOG and Loguru use /// for compatibility, on by default #if defined(JOURNAL_GLOG_COMPAT) namespace journal { constexpr auto JournalGLogVerbosity_ERROR = detail::LogVerbosity::Error; constexpr auto JournalGLogVerbosity_WARNING = detail::LogVerbosity::Warn; constexpr auto JournalGLogVerbosity_WARN = detail::LogVerbosity::Warn; constexpr auto JournalGLogVerbosity_INFO = detail::LogVerbosity::Info; constexpr auto JournalGLogVerbosity_DEBUG = detail::LogVerbosity::Debug; constexpr auto JournalGLogVerbosity_TRACE = detail::LogVerbosity::Trace; struct GLogCompatHelper { const detail::source_location source; const detail::LogVerbosity verbosity; consteval GLogCompatHelper(const detail::LogVerbosity &verbosity, const detail::source_location &source = detail::source_location::current()) noexcept : source(source), verbosity(verbosity) {} template auto log(std::string_view fmt, Ts &&...args) const -> void { detail::log(verbosity, source, fmt, std::forward(args)...); } }; } // namespace journal #define LOG_F(V, ...) \ journal::GLogCompatHelper(journal::JournalGLogVerbosity_##V, \ journal::detail::source_location::current()) \ .log(__VA_ARGS__); #endif