Pottu
ContextBase.hpp
Go to the documentation of this file.
1 
7 #ifndef H_POTTU_CONTEXTBASE
8 #define H_POTTU_CONTEXTBASE
9 
10 #include <fmt/base.h>
11 #include <fmt/chrono.h>
12 #include <fmt/color.h>
13 
14 #include <string>
15 #include <iostream>
16 #include <chrono>
17 #include <memory>
18 #include <vector>
19 
20 #include <mutex>
21 
22 
23 namespace pottu {
24 
25  enum loggerlevel_e {
26  LOGLEVEL_NONE = 0,
27  LOGLEVEL_DEBUG = 10,
28  LOGLEVEL_INFO = 20,
29  LOGLEVEL_WARNING = 30,
30  LOGLEVEL_ERROR = 40,
31  LOGLEVEL_CRITICAL = 50
32  };
33 
34 
35  class ContextHandle;
36 
37 
41  struct ContextBase {
42 
52  static void registerContext( ContextBase *context ) {
53  const std::lock_guard<std::mutex> lock(_getMutex());
54  std::unique_ptr<ContextBase> &ctx = _getActiveRef();
55  if( ctx )
56  throw std::runtime_error( "Context is already registered." );
57  ctx.reset( context );
58  }
59 
60  // PRIVATE
61  static std::mutex &_getMutex() noexcept {
62  static std::mutex m;
63  return m;
64  }
65 
66  // PRIVATE
67  static std::unique_ptr<ContextBase> &_getActiveRef() noexcept {
68  static std::unique_ptr<ContextBase> ctx;
69  return ctx;
70  }
71 
72 
80  static ContextBase &getActive() noexcept {
81  const std::lock_guard<std::mutex> lock(_getMutex());
82  std::unique_ptr<ContextBase> &ctx = _getActiveRef();
83  if( !ctx )
84  ctx.reset( new ContextBase() );
85  return *ctx.get();
86  }
87 
88 
94  inline ContextHandle *createHandle( const std::string &name ) noexcept;
95 
96 
97  const char *loglevelToStr( uint8_t level ) const noexcept {
98  if( level < LOGLEVEL_DEBUG )
99  return "none";
100  else if( level < LOGLEVEL_INFO )
101  return "debug";
102  else if( level < LOGLEVEL_WARNING )
103  return "info";
104  else if( level < LOGLEVEL_ERROR )
105  return "warning";
106  else if( level < LOGLEVEL_CRITICAL )
107  return "error";
108  else
109  return "critical";
110  }
111 
112  const fmt::text_style &getStyleForLevel( uint8_t level ) const noexcept {
113  if( level < LOGLEVEL_DEBUG )
114  return styles[0];
115  else if( level < LOGLEVEL_INFO )
116  return styles[1];
117  else if( level < LOGLEVEL_WARNING )
118  return styles[2];
119  else if( level < LOGLEVEL_ERROR )
120  return styles[3];
121  else if( level < LOGLEVEL_CRITICAL )
122  return styles[4];
123  else
124  return styles[5];
125  }
126 
128  static void logDebug( const std::string &message, uint64_t token=0 ) {
129  getActive().handleLogMsg( "", LOGLEVEL_DEBUG, message );
130  }
132  static void logInfo( const std::string &message, uint64_t token=0 ) {
133  getActive().handleLogMsg( "", LOGLEVEL_INFO, message );
134  }
136  static void logWarning( const std::string &message, uint64_t token=0 ) {
137  getActive().handleLogMsg( "", LOGLEVEL_WARNING, message );
138  }
140  static void logError( const std::string &message, uint64_t token=0 ) {
141  getActive().handleLogMsg( "", LOGLEVEL_ERROR, message );
142  }
144  static void logCritical( const std::string &message, uint64_t token=0 ) {
145  getActive().handleLogMsg( "", LOGLEVEL_CRITICAL, message );
146  }
147 
148 
149  inline void printStatistics() noexcept;
150 
151  virtual void handleLogMsg( const std::string &sender, uint8_t level, const std::string &message ) noexcept {
152  const std::lock_guard<std::mutex> lock(_getMutex());
153  auto t = std::chrono::system_clock::now();
154  if( useStyles ) {
155  fmt::print( getStyleForLevel(level), "{:12} {:10} {:%H:%M:%S} {:4}", sender, loglevelToStr(level), t, message );
156  fmt::print( "\n" );
157  } else
158  fmt::print( "{:12} {:10} {:%H:%M:%S} {:4}\n", sender, loglevelToStr(level), t, message );
159  }
160 
161 
162 
163  bool useStyles{true};
164  fmt::text_style styles[6] = {
165  {fg(fmt::color::gray)},
166  {fg(fmt::color::gray)},
167  {},
168  {fmt::emphasis::bold | bg(fmt::color::black) | fg(fmt::color::yellow)},
169  {fg(fmt::color::red)},
170  {fmt::emphasis::bold | fg(fmt::color::red)}
171  };
172 
173  std::vector<std::unique_ptr<ContextHandle>> _handles;
174 
175  };
176 
177 
178 
189  public:
190  ContextHandle( ContextBase &ctx, const std::string &name ) : _ctx(ctx), _name(name) {}
191 
192  void logDebug( const std::string &message, uint64_t token=0 ) { _ctx.handleLogMsg( _name, LOGLEVEL_DEBUG, message ); }
193  void logInfo( const std::string &message, uint64_t token=0 ) { _ctx.handleLogMsg( _name, LOGLEVEL_INFO, message ); }
194  void logWarning( const std::string &message, uint64_t token=0 ) { _ctx.handleLogMsg( _name, LOGLEVEL_WARNING, message ); }
195  void logError( const std::string &message, uint64_t token=0 ) { _ctx.handleLogMsg( _name, LOGLEVEL_ERROR, message ); }
196  void logCritical( const std::string &message, uint64_t token=0 ) { _ctx.handleLogMsg( _name, LOGLEVEL_CRITICAL, message ); }
197 
198  const std::string &getName() const noexcept { return _name; }
199 
200  double getTotalRunTime() const noexcept { return ( std::chrono::duration<double>( _runsDuration ) ).count(); }
201  uint64_t getNumOfRuns() const noexcept { return _runsFinished; }
202 
204  public:
205  ~ProcessInstance() { if( _h ) _h->stopProcess(); }
206  ProcessInstance( ProcessInstance &&o ) : _h(o._h) { o._h = nullptr; }
207  private:
208  friend class ContextHandle;
209  ProcessInstance( ContextHandle *h ) : _h(h) { _h->startProcess(); }
210  ProcessInstance( const ProcessInstance &o ) = delete;
211 
212  ContextHandle *_h;
213  };
214 
215  ProcessInstance processInstance() noexcept {
216  return ProcessInstance( this );
217  }
218 
219  private:
220  friend class ProcessInstance;
221 
222  void startProcess() noexcept {
223  _running = true;
224  _runStart = std::chrono::steady_clock::now();
225  }
226 
227  void stopProcess() noexcept {
228  _running = false;
229  ++_runsFinished;
230  const auto t = std::chrono::steady_clock::now();
231  _runsDuration += t-_runStart;
232  }
233 
234  ContextBase &_ctx;
235  std::string _name;
236 
237  bool _running{false};
238  uint64_t _runsFinished{0};
239  std::chrono::steady_clock::duration _runsDuration{std::chrono::steady_clock::duration(0)};
240  std::chrono::steady_clock::time_point _runStart;
241  };
242 
243 
244 
245 
246 
247  inline ContextHandle *ContextBase::createHandle( const std::string &name ) noexcept {
248  const std::lock_guard<std::mutex> lock(_getMutex());
249  // TODO multiple handles with same name
250 
251  _handles.push_back( std::make_unique<ContextHandle>( *this, name ) );
252  return _handles.back().get();
253  }
254 
255 
256  inline void ContextBase::printStatistics() noexcept {
257  std::string msg;
258  {
259  const std::lock_guard<std::mutex> lock(_getMutex());
260  msg += fmt::format( "Statistics collected:\n" );
261  msg += fmt::format( " name runs time [s]\n" );
262  for( const auto &h : _handles ) {
263  if( h->getNumOfRuns() )
264  msg += fmt::format(" {:32} {:12} {:10.3f}\n", h->getName(), h->getNumOfRuns(), h->getTotalRunTime() );
265  }
266 
267  // Opening the mutex to avoid a dead lock.
268  }
269  handleLogMsg( "Context", LOGLEVEL_INFO, msg );
270  }
271 
272 
273 }
274 
275 
276 #endif
Definition: ContextBase.hpp:203
Handle to context used by specific class.
Definition: ContextBase.hpp:188
Definition: mainpage.dox:6
Default context for printing and collecting statistics.
Definition: ContextBase.hpp:41
ContextHandle * createHandle(const std::string &name) noexcept
Creates a new named handle to the active context.
Definition: ContextBase.hpp:247
static void logInfo(const std::string &message, uint64_t token=0)
Sends log message with level DEBUG from anonymous source.
Definition: ContextBase.hpp:132
static ContextBase & getActive() noexcept
Returns active Context.
Definition: ContextBase.hpp:80
static void logCritical(const std::string &message, uint64_t token=0)
Sends log message with level DEBUG from anonymous source.
Definition: ContextBase.hpp:144
static void registerContext(ContextBase *context)
Registers a context for the whole application.
Definition: ContextBase.hpp:52
static void logWarning(const std::string &message, uint64_t token=0)
Sends log message with level DEBUG from anonymous source.
Definition: ContextBase.hpp:136
static void logDebug(const std::string &message, uint64_t token=0)
Sends log message with level DEBUG from anonymous source.
Definition: ContextBase.hpp:128
static void logError(const std::string &message, uint64_t token=0)
Sends log message with level DEBUG from anonymous source.
Definition: ContextBase.hpp:140