hmbdc
simplify-high-performance-messaging-programming
AsyncLoggerT.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include "hmbdc/app/Base.hpp"
5 #include "hmbdc/text/LfbStream.hpp"
6 #include "hmbdc/time/Time.hpp"
7 #include <string>
8 #include <memory>
9 #include <tuple>
10 
11 #define HMBDC_ALOG_D(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_D(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
12 #define HMBDC_ALOG_N(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_N(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
13 #define HMBDC_ALOG_W(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_W(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
14 #define HMBDC_ALOG_C(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_C(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
15 #define HMBDC_ALOG_DEBUG(x) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_D(#x "=", x, LogTrailer(__FILE__, __LINE__))
16 
17 #define HMBDC_ALOG_d(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_D(__VA_ARGS__, EmptyLogTrailer())
18 #define HMBDC_ALOG_n(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_N(__VA_ARGS__, EmptyLogTrailer())
19 #define HMBDC_ALOG_w(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_W(__VA_ARGS__, EmptyLogTrailer())
20 #define HMBDC_ALOG_c(...) hmbdc::app::utils::AsyncLoggerT<HMBDC_ALOG_CONTEXT>::instance().LOG_C(__VA_ARGS__, EmptyLogTrailer())
21 
22 namespace hmbdc { namespace app { namespace utils {
23 
24 char const g_LogLevelStr[][12] = {
25  "debug : ",
26  "notice: ",
27  "warning: ",
28  "critical: "
29 };
30 
31 /**
32  * @class AsyncLoggerT<>
33  * @brief a high performance async logger that doesn't penalize logging threads as much
34  * when the logging load is heavy
35  * @details see @example hmbdc-log.cpp
36  *
37  */
38 template <typename Ctx>
40 : Client<AsyncLoggerT<Ctx>, LoggingT<Ctx::MAX_MESSAGE_SIZE>>
41 , text::lfb_stream::OStringStream<typename Ctx::Buffer
42  , MessageWrap<LoggingT<Ctx::MAX_MESSAGE_SIZE>>
43  , LoggingT<Ctx::MAX_MESSAGE_SIZE>::typeTag
44  >
45 , pattern::GuardedSingleton<AsyncLoggerT<Ctx>> {
46  static_assert(Ctx::MAX_MESSAGE_SIZE != 0
47  , "HMBDC_ALOG_CONTEXT needs to be 'compile time sized'");
49  friend struct pattern::SingletonGuardian<AsyncLoggerT<Ctx>>;
50 
51  enum Level {
52  L_DEBUG = 0,
53  L_NOTICE,
54  L_WARNING,
55  L_CRITICAL,
56  L_OFF
57  };
58 private:
59  std::ostream& log_;
60  static std::unique_ptr<Ctx> pCtx_s; //Logger is a singleton
61  Ctx& ctx_;
62  Level minLevel_;
63  std::string schedPolicy_;
64  int priority_;
65 
66  using Stream = text::lfb_stream::OStringStream<typename Ctx::Buffer
67  , MessageWrap<Logging>, Logging::typeTag>;
68 
69  AsyncLoggerT(std::ostream& log
70  , uint64_t cpuAffinityMask = 0
71  , char const* schedPolicy = "SCHED_IDLE"
72  , int priority = 0
73  , uint16_t logBufferSizePower2Num = 8)
74  : Stream((pCtx_s = std::unique_ptr<Ctx>(new Ctx(logBufferSizePower2Num)))->buffer())
75  , log_(log)
76  , ctx_(*pCtx_s)
77  , minLevel_(L_DEBUG)
78  , schedPolicy_(schedPolicy)
79  , priority_(priority) {
80  ctx_.start(*this
81  , cpuAffinityMask?cpuAffinityMask:(1ul << std::thread::hardware_concurrency()) - 1ul);
82  }
83 
84  ~AsyncLoggerT() {
85  if (pCtx_s) {
86  pCtx_s->stop();
87  pCtx_s->join();
88  }
89  }
90 
91  AsyncLoggerT(std::ostream& log, Ctx& ctx
92  , char const* schedPolicy = "SCHED_IDLE"
93  , int priority = 0)
94  : Stream(ctx.buffer())
95  , log_(log)
96  , ctx_(ctx)
97  , minLevel_(L_DEBUG)
98  , schedPolicy_(schedPolicy)
99  , priority_(priority) {
100  }
101 
102  struct LogHeader {
103  LogHeader(Level level)
104  : l(level)
105  , ts(hmbdc::time::SysTime::now()) {
106  }
107 
108  Level l;
110 
111  friend std::ostream& operator << (std::ostream& os, LogHeader const& h) {
112  os << h.ts << " " << g_LogLevelStr[h.l];
113  return os;
114  }
115  };
116 
117 public:
118  char const* hmbdcName() const { return "logger"; }
119  void setMinLogLevel(Level minLevel) {
120  minLevel_ = minLevel;
121  }
122 
123  std::tuple<char const*, int> schedSpec() const {
124  return std::make_tuple(schedPolicy_.c_str(), priority_);
125  }
126 
127  template <typename ...Args>
128  void LOG_D(Args&&... args) {
129 #ifndef NDEBUG
130  Stream::operator()(LogHeader(L_DEBUG), std::forward<Args>(args)...);
131 #endif
132  }
133 
134  template <typename ...Args>
135  void LOG_N(Args&&... args) {
136  if (minLevel_ <= L_NOTICE)
137  Stream::operator()(LogHeader(L_NOTICE), std::forward<Args>(args)...);
138  }
139  template <typename ...Args>
140  void LOG_W(Args&&... args) {
141  if (minLevel_ <= L_WARNING)
142  Stream::operator()(LogHeader(L_WARNING), std::forward<Args>(args)...);
143  }
144  template <typename ...Args>
145  void LOG_C(Args&&... args) {
146  if (minLevel_ <= L_CRITICAL)
147  Stream::operator()(LogHeader(L_CRITICAL), std::forward<Args>(args)...);
148  }
149 
150  void handleMessageCb(Logging& logItem) {
151  Stream::dump(log_, logItem);
152  }
153 };
154 
155 template <typename Ctx>
156 std::unique_ptr<Ctx> AsyncLoggerT<Ctx>::pCtx_s;
157 
158 }}}
Definition: Message.hpp:120
base for the Singleton that works with SingletonGuardian
Definition: GuardedSingleton.hpp:35
RAII representing the lifespan of the underlying Singleton which also ganrantees the singularity of u...
Definition: GuardedSingleton.hpp:20
Definition: LfbStream.hpp:82
Definition: Time.hpp:14
Definition: AsyncLoggerT.hpp:102
Definition: Message.hpp:72
A Client represents a thread of execution/a task. The execution is managed by a Context. a Client object could participate in message dispatching as the receiver of specifed message types.
Definition: Client.hpp:47
Definition: Base.hpp:12
a high performance async logger that doesn&#39;t penalize logging threads as much when the logging load i...
Definition: AsyncLoggerT.hpp:39