diff --git a/benchmark/benchmark_log.cpp b/benchmark/benchmark_log.cpp index 7a65212..549bbb8 100644 --- a/benchmark/benchmark_log.cpp +++ b/benchmark/benchmark_log.cpp @@ -6,14 +6,14 @@ namespace { void BM_imp_log_no_output(benchmark::State& state) { - imp::log::gripper log {{}, __func__}; + imp::log::gripper log {__func__, {}}; for (auto _ : state) { log.debug("hello log."); } } void BM_imp_log_gripper(benchmark::State& state) { - imp::log::gripper log {{}, __func__}; + imp::log::gripper log {__func__, {}}; for (auto _ : state) { log.info("hello log."); } diff --git a/include/libimp/log.h b/include/libimp/log.h index d682c24..155fe83 100644 --- a/include/libimp/log.h +++ b/include/libimp/log.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "fmt/format.h" #include "fmt/chrono.h" @@ -53,22 +54,22 @@ template constexpr bool has_fn_output_v = has_fn_output::type::value; struct vtable_t { - void (*output)(void *, log::level, std::string &&); + void (*output)(void *, log::level, std::string &&) noexcept; }; template class traits { template static auto make_fn_output() noexcept - -> std::enable_if_t, void (*)(void *, log::level, std::string &&)> { - return [](void *p, log::level l, std::string &&s) { + -> std::enable_if_t, void (*)(void *, log::level, std::string &&) noexcept> { + return [](void *p, log::level l, std::string &&s) noexcept { static_cast(p)->output(l, std::move(s)); }; } template static auto make_fn_output() noexcept - -> std::enable_if_t, void (*)(void *, log::level, std::string &&)> { - return [](void *, log::level, std::string &&) {}; + -> std::enable_if_t, void (*)(void *, log::level, std::string &&) noexcept> { + return [](void *, log::level, std::string &&) noexcept {}; } public: @@ -98,12 +99,12 @@ public: explicit operator bool() const noexcept; - void output(log::level, std::string &&); + void output(log::level, std::string &&) noexcept; }; class LIBIMP_EXPORT std_t { public: - void output(log::level, std::string &&); + void output(log::level, std::string &&) noexcept; }; LIBIMP_EXPORT extern std_t std_out; @@ -114,51 +115,58 @@ class gripper { level level_limit_; template - gripper &output(log::level l, Fmt &&ft, A &&... args) { + gripper &output(log::level l, Fmt &&ft, A &&... args) noexcept { if (!printer_ || (enum_cast(l) < enum_cast(level_limit_))) { return *this; } constexpr static char types[] = { 'T', 'D', 'I', 'W', 'E', 'F' }; - auto tp = std::chrono::system_clock::now(); - auto ms = std::chrono::time_point_cast(tp).time_since_epoch().count() % 1000; - auto px = fmt("[{}][{:%Y-%m-%d %H:%M:%S}.{:03}][{}] ", types[enum_cast(l)], tp, ms, func_); - printer_.output(l, std::move(px += fmt(std::forward(ft), std::forward(args)...))); + try { + auto tp = std::chrono::system_clock::now(); + auto ms = std::chrono::time_point_cast(tp).time_since_epoch().count() % 1000; + auto px = fmt("[{}][{:%Y-%m-%d %H:%M:%S}.{:03}][{}] ", types[enum_cast(l)], tp, ms, func_); + printer_.output(l, std::move(px += fmt(std::forward(ft), std::forward(args)...))); + } catch (std::exception const &e) { + /// @brief [TBD] std::string constructor may throw an exception + printer_.output(level::failed, e.what()); + } return *this; } public: - gripper(printer printer, char const *func, level level_limit = level::info) noexcept + gripper(char const *func, printer printer = std_out, level level_limit = level::info) noexcept : printer_ (printer) , func_ (func) , level_limit_(level_limit) {} template - gripper &trace(Fmt &&ft, A &&... args) { + gripper &trace(Fmt &&ft, A &&... args) noexcept { return output(log::level::trace, std::forward(ft), std::forward(args)...); } template - gripper &debug(Fmt &&ft, A &&... args) { + gripper &debug(Fmt &&ft, A &&... args) noexcept { return output(log::level::debug, std::forward(ft), std::forward(args)...); } template - gripper &info(Fmt &&ft, A &&... args) { + gripper &info(Fmt &&ft, A &&... args) noexcept { return output(log::level::info, std::forward(ft), std::forward(args)...); } template - gripper &warning(Fmt &&ft, A &&... args) { + gripper &warning(Fmt &&ft, A &&... args) noexcept { return output(log::level::warning, std::forward(ft), std::forward(args)...); } template - gripper &error(Fmt &&ft, A &&... args) { + gripper &error(Fmt &&ft, A &&... args) noexcept { return output(log::level::error, std::forward(ft), std::forward(args)...); } template - gripper &failed(Fmt &&ft, A &&... args) { + gripper &failed(Fmt &&ft, A &&... args) noexcept { return output(log::level::failed, std::forward(ft), std::forward(args)...); } }; } // namespace log LIBIMP_NAMESPACE_END_ + +#define LIBIMP_LOG_(...) LIBIMP_NAMESPACE_::log::gripper log {__func__, __VA_ARGS__} \ No newline at end of file diff --git a/src/libimp/log.cpp b/src/libimp/log.cpp index 17f5b2a..aa10dca 100644 --- a/src/libimp/log.cpp +++ b/src/libimp/log.cpp @@ -11,14 +11,14 @@ printer::operator bool() const noexcept { return (objp_ != nullptr) && (vtable_ != nullptr); } -void printer::output(log::level l, std::string &&s) { +void printer::output(log::level l, std::string &&s) noexcept { if (!*this) return; vtable_->output(objp_, l, std::move(s)); } std_t std_out; -void std_t::output(log::level l, std::string &&s) { +void std_t::output(log::level l, std::string &&s) noexcept { switch (l) { case level::trace: case level::debug: diff --git a/test/test_imp_log.cpp b/test/test_imp_log.cpp index f5eaaca..69e7953 100644 --- a/test/test_imp_log.cpp +++ b/test/test_imp_log.cpp @@ -68,6 +68,12 @@ TEST(log, log_printer) { } TEST(log, gripper) { - imp::log::gripper log {imp::log::std_out, __func__}; - log.info("hello"); + { + imp::log::gripper log {__func__}; + log.info("hello"); + } + { + LIBIMP_LOG_(); + log.info("hello 2"); + } } \ No newline at end of file