add: [log] exception handling for log printing

This commit is contained in:
mutouyun 2022-08-07 17:51:30 +08:00
parent 3522061321
commit 56ee0e12df
4 changed files with 39 additions and 25 deletions

View File

@ -6,14 +6,14 @@
namespace { namespace {
void BM_imp_log_no_output(benchmark::State& state) { void BM_imp_log_no_output(benchmark::State& state) {
imp::log::gripper log {{}, __func__}; imp::log::gripper log {__func__, {}};
for (auto _ : state) { for (auto _ : state) {
log.debug("hello log."); log.debug("hello log.");
} }
} }
void BM_imp_log_gripper(benchmark::State& state) { void BM_imp_log_gripper(benchmark::State& state) {
imp::log::gripper log {{}, __func__}; imp::log::gripper log {__func__, {}};
for (auto _ : state) { for (auto _ : state) {
log.info("hello log."); log.info("hello log.");
} }

View File

@ -9,6 +9,7 @@
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <chrono> #include <chrono>
#include <exception>
#include "fmt/format.h" #include "fmt/format.h"
#include "fmt/chrono.h" #include "fmt/chrono.h"
@ -53,22 +54,22 @@ template <typename T>
constexpr bool has_fn_output_v = has_fn_output<T>::type::value; constexpr bool has_fn_output_v = has_fn_output<T>::type::value;
struct vtable_t { struct vtable_t {
void (*output)(void *, log::level, std::string &&); void (*output)(void *, log::level, std::string &&) noexcept;
}; };
template <typename T> template <typename T>
class traits { class traits {
template <typename U> template <typename U>
static auto make_fn_output() noexcept static auto make_fn_output() noexcept
-> std::enable_if_t<has_fn_output_v<U>, void (*)(void *, log::level, std::string &&)> { -> std::enable_if_t<has_fn_output_v<U>, void (*)(void *, log::level, std::string &&) noexcept> {
return [](void *p, log::level l, std::string &&s) { return [](void *p, log::level l, std::string &&s) noexcept {
static_cast<U *>(p)->output(l, std::move(s)); static_cast<U *>(p)->output(l, std::move(s));
}; };
} }
template <typename U> template <typename U>
static auto make_fn_output() noexcept static auto make_fn_output() noexcept
-> std::enable_if_t<!has_fn_output_v<U>, void (*)(void *, log::level, std::string &&)> { -> std::enable_if_t<!has_fn_output_v<U>, void (*)(void *, log::level, std::string &&) noexcept> {
return [](void *, log::level, std::string &&) {}; return [](void *, log::level, std::string &&) noexcept {};
} }
public: public:
@ -98,12 +99,12 @@ public:
explicit operator bool() const noexcept; explicit operator bool() const noexcept;
void output(log::level, std::string &&); void output(log::level, std::string &&) noexcept;
}; };
class LIBIMP_EXPORT std_t { class LIBIMP_EXPORT std_t {
public: public:
void output(log::level, std::string &&); void output(log::level, std::string &&) noexcept;
}; };
LIBIMP_EXPORT extern std_t std_out; LIBIMP_EXPORT extern std_t std_out;
@ -114,51 +115,58 @@ class gripper {
level level_limit_; level level_limit_;
template <typename Fmt, typename... A> template <typename Fmt, typename... A>
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_))) { if (!printer_ || (enum_cast(l) < enum_cast(level_limit_))) {
return *this; return *this;
} }
constexpr static char types[] = { constexpr static char types[] = {
'T', 'D', 'I', 'W', 'E', 'F' 'T', 'D', 'I', 'W', 'E', 'F'
}; };
auto tp = std::chrono::system_clock::now(); try {
auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>(tp).time_since_epoch().count() % 1000; auto tp = std::chrono::system_clock::now();
auto px = fmt("[{}][{:%Y-%m-%d %H:%M:%S}.{:03}][{}] ", types[enum_cast(l)], tp, ms, func_); auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>(tp).time_since_epoch().count() % 1000;
printer_.output(l, std::move(px += fmt(std::forward<Fmt>(ft), std::forward<A>(args)...))); 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<Fmt>(ft), std::forward<A>(args)...)));
} catch (std::exception const &e) {
/// @brief [TBD] std::string constructor may throw an exception
printer_.output(level::failed, e.what());
}
return *this; return *this;
} }
public: 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) : printer_ (printer)
, func_ (func) , func_ (func)
, level_limit_(level_limit) {} , level_limit_(level_limit) {}
template <typename Fmt, typename... A> template <typename Fmt, typename... A>
gripper &trace(Fmt &&ft, A &&... args) { gripper &trace(Fmt &&ft, A &&... args) noexcept {
return output(log::level::trace, std::forward<Fmt>(ft), std::forward<A>(args)...); return output(log::level::trace, std::forward<Fmt>(ft), std::forward<A>(args)...);
} }
template <typename Fmt, typename... A> template <typename Fmt, typename... A>
gripper &debug(Fmt &&ft, A &&... args) { gripper &debug(Fmt &&ft, A &&... args) noexcept {
return output(log::level::debug, std::forward<Fmt>(ft), std::forward<A>(args)...); return output(log::level::debug, std::forward<Fmt>(ft), std::forward<A>(args)...);
} }
template <typename Fmt, typename... A> template <typename Fmt, typename... A>
gripper &info(Fmt &&ft, A &&... args) { gripper &info(Fmt &&ft, A &&... args) noexcept {
return output(log::level::info, std::forward<Fmt>(ft), std::forward<A>(args)...); return output(log::level::info, std::forward<Fmt>(ft), std::forward<A>(args)...);
} }
template <typename Fmt, typename... A> template <typename Fmt, typename... A>
gripper &warning(Fmt &&ft, A &&... args) { gripper &warning(Fmt &&ft, A &&... args) noexcept {
return output(log::level::warning, std::forward<Fmt>(ft), std::forward<A>(args)...); return output(log::level::warning, std::forward<Fmt>(ft), std::forward<A>(args)...);
} }
template <typename Fmt, typename... A> template <typename Fmt, typename... A>
gripper &error(Fmt &&ft, A &&... args) { gripper &error(Fmt &&ft, A &&... args) noexcept {
return output(log::level::error, std::forward<Fmt>(ft), std::forward<A>(args)...); return output(log::level::error, std::forward<Fmt>(ft), std::forward<A>(args)...);
} }
template <typename Fmt, typename... A> template <typename Fmt, typename... A>
gripper &failed(Fmt &&ft, A &&... args) { gripper &failed(Fmt &&ft, A &&... args) noexcept {
return output(log::level::failed, std::forward<Fmt>(ft), std::forward<A>(args)...); return output(log::level::failed, std::forward<Fmt>(ft), std::forward<A>(args)...);
} }
}; };
} // namespace log } // namespace log
LIBIMP_NAMESPACE_END_ LIBIMP_NAMESPACE_END_
#define LIBIMP_LOG_(...) LIBIMP_NAMESPACE_::log::gripper log {__func__, __VA_ARGS__}

View File

@ -11,14 +11,14 @@ printer::operator bool() const noexcept {
return (objp_ != nullptr) && (vtable_ != nullptr); 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; if (!*this) return;
vtable_->output(objp_, l, std::move(s)); vtable_->output(objp_, l, std::move(s));
} }
std_t std_out; 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) { switch (l) {
case level::trace: case level::trace:
case level::debug: case level::debug:

View File

@ -68,6 +68,12 @@ TEST(log, log_printer) {
} }
TEST(log, gripper) { 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");
}
} }