From df3890d0c5169c090eaaad909fb9c6369580afb7 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 29 May 2022 17:58:37 +0800 Subject: [PATCH] fix: [log] adjust code interface and fix bugs --- benchmark/benchmark_log.cpp | 8 ++ include/libimp/log.h | 234 +++++++++++++++++++----------------- src/libimp/log.cpp | 38 +++--- test/test_imp_log.cpp | 57 ++++----- 4 files changed, 176 insertions(+), 161 deletions(-) diff --git a/benchmark/benchmark_log.cpp b/benchmark/benchmark_log.cpp index 696839b..7a65212 100644 --- a/benchmark/benchmark_log.cpp +++ b/benchmark/benchmark_log.cpp @@ -5,6 +5,13 @@ namespace { +void BM_imp_log_no_output(benchmark::State& state) { + 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__}; for (auto _ : state) { @@ -14,4 +21,5 @@ void BM_imp_log_gripper(benchmark::State& state) { } // namespace +BENCHMARK(BM_imp_log_no_output); BENCHMARK(BM_imp_log_gripper); \ No newline at end of file diff --git a/include/libimp/log.h b/include/libimp/log.h index 1e2a9a1..d682c24 100644 --- a/include/libimp/log.h +++ b/include/libimp/log.h @@ -16,108 +16,9 @@ #include "libimp/def.h" #include "libimp/detect_plat.h" #include "libimp/export.h" +#include "libimp/enum_cast.h" LIBIMP_NAMESPACE_BEG_ - -namespace detail_log { - -template -class has_fn_info { - static std::false_type check(...); - template - static auto check(U *u) -> decltype(u->info(std::declval()), std::true_type{}); - -public: - using type = decltype(check(static_cast(nullptr))); -}; - -template -constexpr bool has_fn_info_v = has_fn_info::type::value; - -template -class has_fn_error { - static std::false_type check(...); - template - static auto check(U *u) -> decltype(u->error(std::declval()), std::true_type{}); - -public: - using type = decltype(check(static_cast(nullptr))); -}; - -template -constexpr bool has_fn_error_v = has_fn_error::type::value; - -struct vtable_t { - void (*info )(void *, std::string &&); - void (*error)(void *, std::string &&); -}; - -template -class traits { - template - static auto make_fn_info() noexcept - -> std::enable_if_t, void (*)(void *, std::string &&)> { - return [](void *p, std::string &&s) { - static_cast(p)->info(std::move(s)); - }; - } - template - static auto make_fn_info() noexcept - -> std::enable_if_t, void (*)(void *, std::string &&)> { - return [](void *, std::string &&) {}; - } - - template - static auto make_fn_error() noexcept - -> std::enable_if_t, void (*)(void *, std::string &&)> { - return [](void *p, std::string &&s) { - static_cast(p)->error(std::move(s)); - }; - } - template - static auto make_fn_error() noexcept - -> std::enable_if_t, void (*)(void *, std::string &&)> { - return [](void *, std::string &&) {}; - } - -public: - static auto make_vtable() noexcept { - static vtable_t vt { - make_fn_info (), - make_fn_error(), - }; - return &vt; - } -}; - -} // namespace detail_log - -class LIBIMP_EXPORT log_printer { - void *objp_ {nullptr}; - detail_log::vtable_t *vtable_ {nullptr}; - -public: - log_printer() noexcept = default; - - template - log_printer(T &p) noexcept - : objp_ (static_cast(&p)) - , vtable_(detail_log::traits::make_vtable()) {} - - explicit operator bool() const noexcept; - - void info (std::string &&); - void error(std::string &&); -}; - -class LIBIMP_EXPORT log_std_t { -public: - void info (std::string &&) const; - void error(std::string &&) const; -}; - -LIBIMP_EXPORT extern log_std_t log_std; - namespace log { template @@ -125,30 +26,137 @@ std::string fmt(Fmt &&ft, A &&... args) { return ::fmt::format(std::forward(ft), std::forward(args)...); } -class LIBIMP_EXPORT gripper { - log_printer printer_; - char const *func_; +enum class level : std::int32_t { + trace, + debug, + info, + warning, + error, + failed, +}; - gripper &output(void (log_printer::*out_fn)(std::string &&), char type, std::string &&log_str) { - auto tm = std::chrono::system_clock::now(); - auto ms = std::chrono::time_point_cast(tm).time_since_epoch().count() % 1000; - auto px = fmt("[{}][{:%Y-%m-%d %H:%M:%S}.{:03}][{}]\n", type, tm, ms, func_); - (printer_.*out_fn)(std::move(px += std::move(log_str))); +} // namespace log + +namespace detail_log { + +template +class has_fn_output { + static std::false_type check(...); + template + static auto check(U *u) -> decltype(u->output(log::level::trace, std::declval()), std::true_type{}); + +public: + using type = decltype(check(static_cast(nullptr))); +}; + +template +constexpr bool has_fn_output_v = has_fn_output::type::value; + +struct vtable_t { + void (*output)(void *, log::level, std::string &&); +}; + +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) { + 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 &&) {}; + } + +public: + static auto make_vtable() noexcept { + static vtable_t vt { + make_fn_output(), + }; + return &vt; + } +}; + +} // namespace detail_log + +namespace log { + +class LIBIMP_EXPORT printer { + void *objp_ {nullptr}; + detail_log::vtable_t *vtable_ {nullptr}; + +public: + printer() noexcept = default; + + template + printer(T &p) noexcept + : objp_ (static_cast(&p)) + , vtable_(detail_log::traits::make_vtable()) {} + + explicit operator bool() const noexcept; + + void output(log::level, std::string &&); +}; + +class LIBIMP_EXPORT std_t { +public: + void output(log::level, std::string &&); +}; + +LIBIMP_EXPORT extern std_t std_out; + +class gripper { + printer printer_; + char const *func_; + level level_limit_; + + template + gripper &output(log::level l, Fmt &&ft, A &&... args) { + 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)...))); return *this; } public: - gripper(log_printer printer, char const *func) noexcept - : printer_(printer) - , func_ (func) {} + gripper(printer printer, char const *func, level level_limit = level::info) noexcept + : printer_ (printer) + , func_ (func) + , level_limit_(level_limit) {} + template + gripper &trace(Fmt &&ft, A &&... args) { + return output(log::level::trace, std::forward(ft), std::forward(args)...); + } + template + gripper &debug(Fmt &&ft, A &&... args) { + return output(log::level::debug, std::forward(ft), std::forward(args)...); + } template gripper &info(Fmt &&ft, A &&... args) { - return output(&log_printer::info, 'I', fmt(std::forward(ft), std::forward(args)...)); + return output(log::level::info, std::forward(ft), std::forward(args)...); + } + template + gripper &warning(Fmt &&ft, A &&... args) { + return output(log::level::warning, std::forward(ft), std::forward(args)...); } template gripper &error(Fmt &&ft, A &&... args) { - return output(&log_printer::error, 'E', fmt(std::forward(ft), std::forward(args)...)); + return output(log::level::error, std::forward(ft), std::forward(args)...); + } + template + gripper &failed(Fmt &&ft, A &&... args) { + return output(log::level::failed, std::forward(ft), std::forward(args)...); } }; diff --git a/src/libimp/log.cpp b/src/libimp/log.cpp index c2ad1a8..17f5b2a 100644 --- a/src/libimp/log.cpp +++ b/src/libimp/log.cpp @@ -5,29 +5,35 @@ #include "libimp/log.h" LIBIMP_NAMESPACE_BEG_ +namespace log { -log_printer::operator bool() const noexcept { +printer::operator bool() const noexcept { return (objp_ != nullptr) && (vtable_ != nullptr); } -void log_printer::info(std::string && s) { +void printer::output(log::level l, std::string &&s) { if (!*this) return; - vtable_->info(objp_, std::move(s)); + vtable_->output(objp_, l, std::move(s)); } -void log_printer::error(std::string && s) { - if (!*this) return; - vtable_->error(objp_, std::move(s)); -} - -log_std_t log_std; - -void log_std_t::info(std::string && s) const { - std::fprintf(stdin, "%s", s.c_str()); -} - -void log_std_t::error(std::string && s) const { - std::fprintf(stderr, "%s", s.c_str()); +std_t std_out; + +void std_t::output(log::level l, std::string &&s) { + switch (l) { + case level::trace: + case level::debug: + case level::info: + std::fprintf(stdout, "%s\n", s.c_str()); + break; + case level::warning: + case level::error: + case level::failed: + std::fprintf(stderr, "%s\n", s.c_str()); + break; + default: + break; + } } +} // namespace log LIBIMP_NAMESPACE_END_ diff --git a/test/test_imp_log.cpp b/test/test_imp_log.cpp index db55eaa..f5eaaca 100644 --- a/test/test_imp_log.cpp +++ b/test/test_imp_log.cpp @@ -4,49 +4,43 @@ #include "libimp/log.h" TEST(log, detail) { - EXPECT_FALSE(imp::detail_log::has_fn_info_v); - EXPECT_FALSE(imp::detail_log::has_fn_error_v); + EXPECT_FALSE(imp::detail_log::has_fn_output_v); struct foo { int info(std::string); }; - EXPECT_TRUE (imp::detail_log::has_fn_info_v); - EXPECT_FALSE(imp::detail_log::has_fn_error_v); + EXPECT_FALSE(imp::detail_log::has_fn_output_v); struct bar { int info(char const *); - void error(std::string &&); + void output(imp::log::level, std::string &&); }; - EXPECT_FALSE(imp::detail_log::has_fn_info_v); - EXPECT_TRUE (imp::detail_log::has_fn_error_v); + EXPECT_TRUE(imp::detail_log::has_fn_output_v); struct str { str(std::string const &); }; struct foo_bar { - void info(std::string const &); - void error(str); + void output(imp::log::level, str); }; - EXPECT_TRUE(imp::detail_log::has_fn_info_v); - EXPECT_TRUE(imp::detail_log::has_fn_error_v); + EXPECT_TRUE(imp::detail_log::has_fn_output_v); auto vt_int = imp::detail_log::traits::make_vtable(); EXPECT_NE(vt_int, nullptr); - vt_int->info (nullptr, "123"); - vt_int->error(nullptr, "321"); + vt_int->output(nullptr, imp::log::level::debug, "123"); struct log { std::string what; - void error(std::string &&s) { - what += s; + void output(imp::log::level l, std::string &&s) { + if (l == imp::log::level::error) what += s; } } ll; auto vt_log = imp::detail_log::traits::make_vtable(); EXPECT_NE(vt_log, nullptr); - vt_log->info (&ll, "123"); - vt_log->error(&ll, "321"); - vt_log->info (&ll, "654"); - vt_log->error(&ll, "456"); + vt_log->output(&ll, imp::log::level::info , "123"); + vt_log->output(&ll, imp::log::level::error, "321"); + vt_log->output(&ll, imp::log::level::info , "654"); + vt_log->output(&ll, imp::log::level::error, "456"); EXPECT_EQ(ll.what, "321456"); } @@ -54,27 +48,26 @@ TEST(log, log_printer) { struct log { std::string i; std::string e; - void info(std::string &&s) { - i += s; - } - void error(std::string &&s) { - e += s; + + void output(imp::log::level l, std::string &&s) { + if (l == imp::log::level::error) e += s; + else if (l == imp::log::level::info) i += s; } } ll; - imp::log_printer pt = ll; - pt.info("hello "); - pt.error("failed: "); - pt.info("log-pt"); - pt.error("whatever"); + imp::log::printer pt = ll; + pt.output(imp::log::level::info , "hello "); + pt.output(imp::log::level::error, "failed: "); + pt.output(imp::log::level::info , "log-pt"); + pt.output(imp::log::level::error, "whatever"); EXPECT_EQ(ll.i, "hello log-pt"); EXPECT_EQ(ll.e, "failed: whatever"); - imp::log_printer ps = imp::log_std; - ps.info("hello world\n"); + imp::log::printer ps = imp::log::std_out; + ps.output(imp::log::level::info, "hello world\n"); } TEST(log, gripper) { - imp::log::gripper log {imp::log_std, __func__}; + imp::log::gripper log {imp::log::std_out, __func__}; log.info("hello"); } \ No newline at end of file