hmbdc
simplify-high-performance-messaging-programming
LoggerT.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include "hmbdc/app/Client.hpp"
5 #include "hmbdc/text/LfbStream.hpp"
6 #include "hmbdc/time/Time.hpp"
7 #include "hmbdc/pattern/GuardedSingleton.hpp"
8 
9 #ifdef HMBDC_LOG_CONTEXT //if defined it has to be 'compile time sized' Context
10 #include "hmbdc/app/Context.hpp"
11 #include <iostream>
12 #include <string>
13 #include <memory>
14 #include <tuple>
15 
16 #define HMBDC_LOG_D(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_D(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
17 #define HMBDC_LOG_N(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_N(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
18 #define HMBDC_LOG_W(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_W(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
19 #define HMBDC_LOG_C(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_C(__VA_ARGS__, LogTrailer(__FILE__, __LINE__))
20 #define HMBDC_LOG_DEBUG(x) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_D(#x "=", x, LogTrailer(__FILE__, __LINE__))
21 
22 #define HMBDC_LOG_d(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_D(__VA_ARGS__, EmptyLogTrailer())
23 #define HMBDC_LOG_n(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_N(__VA_ARGS__, EmptyLogTrailer())
24 #define HMBDC_LOG_w(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_W(__VA_ARGS__, EmptyLogTrailer())
25 #define HMBDC_LOG_c(...) hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>::instance().LOG_C(__VA_ARGS__, EmptyLogTrailer())
26 
27 #define HMBDC_LOGGER hmbdc::app::LoggerT<HMBDC_LOG_CONTEXT>
28 
29 #else
30 
31 #define HMBDC_LOG_D(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[0], __VA_ARGS__, LogTrailer(__FILE__, __LINE__))
32 #define HMBDC_LOG_N(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[1], __VA_ARGS__, LogTrailer(__FILE__, __LINE__))
33 #define HMBDC_LOG_W(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[2], __VA_ARGS__, LogTrailer(__FILE__, __LINE__))
34 #define HMBDC_LOG_C(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[3], __VA_ARGS__, LogTrailer(__FILE__, __LINE__))
35 #define HMBDC_LOG_DEBUG(x) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[0], #x "=", x, LogTrailer(__FILE__, __LINE__))
36 #define HMBDC_LOG_d(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[0], __VA_ARGS__, '\n')
37 #define HMBDC_LOG_n(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[1], __VA_ARGS__, '\n')
38 #define HMBDC_LOG_w(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[2], __VA_ARGS__, '\n')
39 #define HMBDC_LOG_c(...) if (&hmbdc::app::SimpleLogger::instance()) hmbdc::app::SimpleLogger::instance().log(time::SysTime::now(), g_SimpleLogLevelStr[3], __VA_ARGS__, '\n')
40 
41 #define HMBDC_LOGGER hmbdc::app::SimpleLogger
42 #endif //HMBDC_LOG_CONTEXT
43 
44 namespace hmbdc { namespace app {
45 
46 using namespace hmbdc;
47 using namespace hmbdc::pattern;
48 using namespace hmbdc::text;
49 
50 char const g_LogLevelStr[][12] = {
51  "DEBUG : ",
52  "NOTICE: ",
53  "WARNING: ",
54  "CRITICAL: "
55 };
56 
57 char const g_SimpleLogLevelStr[][12 + 1] = {
58  " debug : ",
59  " notice: ",
60  " warning: ",
61  " critical: "
62 };
63 
64 struct LogTrailer {
65  LogTrailer(char const* const file, int line)
66  : f(file)
67  , l(line) {
68  }
69  char const* const f;
70  int l;
71 
72  friend std::ostream& operator << (std::ostream& os, LogTrailer const& t) {
73  os << ' ' << t.f << ':' << t.l << std::endl;
74  return os;
75  }
76 };
78  friend std::ostream& operator << (std::ostream& os, EmptyLogTrailer const&) {
79  os << std::endl;
80  return os;
81  }
82 };
83 
84 /**
85  * @brief a high performance async logger that doesn't penalize logging threads
86  * @details see @example hmbdc-log.cpp
87  *
88  */
89 template <typename Ctx>
90 struct LoggerT
91 : Client<LoggerT<Ctx>, LoggingT<Ctx::MAX_MESSAGE_SIZE>>
92 , lfb_stream::OStringStream<typename Ctx::Buffer
93  , MessageWrap<LoggingT<Ctx::MAX_MESSAGE_SIZE>>
94  , LoggingT<Ctx::MAX_MESSAGE_SIZE>::typeTag
95  >
96 , GuardedSingleton<LoggerT<Ctx>> {
97  static_assert(Ctx::MAX_MESSAGE_SIZE != 0
98  , "HMBDC_LOG_CONTEXT needs to be 'compile time sized'");
100  friend class SingletonGuardian<LoggerT<Ctx>>;
101 
102  enum Level {
103  L_DEBUG = 0,
104  L_NOTICE,
105  L_WARNING,
106  L_CRITICAL,
107  L_OFF
108  };
109 private:
110  std::ostream& log_;
111  static std::unique_ptr<Ctx> pCtx_s; //Logger is a singleton
112  Ctx& ctx_;
113  Level minLevel_;
114  std::string schedPolicy_;
115  int priority_;
116 
117  using Stream = lfb_stream::OStringStream<typename Ctx::Buffer
118  , MessageWrap<Logging>, Logging::typeTag>;
119 
120  LoggerT(std::ostream& log
121  , uint64_t cpuAffinityMask = 0
122  , char const* schedPolicy = "SCHED_IDLE"
123  , int priority = 0
124  , uint16_t logBufferSizePower2Num = 8)
125  : Stream((pCtx_s = std::unique_ptr<Ctx>(new Ctx(logBufferSizePower2Num)))->buffer())
126  , log_(log)
127  , ctx_(*pCtx_s)
128  , minLevel_(L_DEBUG)
129  , schedPolicy_(schedPolicy)
130  , priority_(priority) {
131 #ifdef HMBDC_LOG_CONTEXT
132  ctx_.start(*this
133  , cpuAffinityMask?cpuAffinityMask:(1ul << std::thread::hardware_concurrency()) - 1ul);
134 #endif
135  }
136 
137  ~LoggerT() {
138  if (pCtx_s) {
139  pCtx_s->stop();
140  pCtx_s->join();
141  }
142  }
143 
144  LoggerT(std::ostream& log, Ctx& ctx
145  , char const* schedPolicy = "SCHED_IDLE"
146  , int priority = 0)
147  : Stream(ctx.buffer())
148  , log_(log)
149  , ctx_(ctx)
150  , minLevel_(L_DEBUG)
151  , schedPolicy_(schedPolicy)
152  , priority_(priority) {
153  }
154 
155  struct LogHeader {
156  LogHeader(Level level)
157  : l(level)
158  , ts(time::SysTime::now()) {
159  }
160 
161  Level l;
162  time::SysTime ts;
163 
164  friend std::ostream& operator << (std::ostream& os, LogHeader const& h) {
165  os << h.ts << " " << g_LogLevelStr[h.l];
166  return os;
167  }
168  };
169 
170 public:
171  char const* hmbdcName() const { return "logger"; }
172  void setMinLogLevel(Level minLevel) {
173  minLevel_ = minLevel;
174  }
175 
176  std::tuple<char const*, int> schedSpec() const {
177  return std::make_tuple(schedPolicy_.c_str(), priority_);
178  }
179 
180  template <typename ...Args>
181  void LOG_D(Args&&... args) {
182 #ifndef NDEBUG
183  Stream::operator()(LogHeader(L_DEBUG), std::forward<Args>(args)...);
184 #endif
185  }
186 
187  template <typename ...Args>
188  void LOG_N(Args&&... args) {
189  if (minLevel_ <= L_NOTICE)
190  Stream::operator()(LogHeader(L_NOTICE), std::forward<Args>(args)...);
191  }
192  template <typename ...Args>
193  void LOG_W(Args&&... args) {
194  if (minLevel_ <= L_WARNING)
195  Stream::operator()(LogHeader(L_WARNING), std::forward<Args>(args)...);
196  }
197  template <typename ...Args>
198  void LOG_C(Args&&... args) {
199  if (minLevel_ <= L_CRITICAL)
200  Stream::operator()(LogHeader(L_CRITICAL), std::forward<Args>(args)...);
201  }
202 
203  void handleMessageCb(Logging& logItem) {
204  Stream::dump(log_, logItem);
205  }
206 };
207 
208 template <typename Ctx>
209 std::unique_ptr<Ctx> LoggerT<Ctx>::pCtx_s;
210 
211 /**
212  * @brief a very naive logger that works safely
213  * @details when HMBDC_LOG_CONTEXT is undefined, you get functionality of this
214  *
215  */
216 struct SimpleLogger : GuardedSingleton<SimpleLogger> {
217  friend class SingletonGuardian<SimpleLogger>;
218  template <typename Arg, typename ...Args>
219  void log(Arg&& arg, Args&&... args) {
220  log_ << std::forward<Arg>(arg);
221  log(std::forward<Args>(args)...);
222  }
223  void log() {
224  }
225 
226 private:
227  template <typename ... NoOpArgs>
228  SimpleLogger(std::ostream& log, NoOpArgs&&...)
229  : log_(log)
230  {}
231  std::ostream& log_;
232 };
233 }}
234 
a very naive logger that works safely
Definition: LoggerT.hpp:216
Definition: LoggerT.hpp:90
Definition: Message.hpp:94
Definition: GuardedSingleton.hpp:19
Definition: GuardedSingleton.hpp:12
Definition: LoggerT.hpp:77
Definition: GuardedSingleton.hpp:9
Definition: LfbStream.hpp:82
Definition: Time.hpp:15
Definition: Message.hpp:46
Definition: Client.hpp:39
Definition: Client.hpp:11
Definition: LfbStream.hpp:11
Definition: LoggerT.hpp:64