RBControl
Library for the RB3201-RBControl board with the ESP32 by RoboticsBrno.
logging.hpp
Go to the documentation of this file.
1 #pragma once
2 #include "format.hpp"
3 #include <iostream>
4 #include <memory>
5 #include <mutex>
6 #include <sys/time.h>
7 #include <vector>
8 
10 enum Verbosity {
11  NOTHING = -100,
12 
13  PANIC = -3,
14  ERROR = -2,
15  WARNING = -1,
16  INFO = 0,
17  DEBUG = 1,
18 
19  ALL = 100
20 };
21 
22 template <class String>
23 class BaseLogSink {
24 public:
25  virtual void log(Verbosity verb, const String& tag, const String& message, uint64_t timestamp) = 0;
26 };
27 
28 template <class String, class Mutex, class Clock>
29 class BaseLogger {
30 public:
31  void addSink(Verbosity threshold, std::unique_ptr<BaseLogSink<String>>&& sink) {
32  _sinks.emplace_back(threshold, std::move(sink));
33  }
34 
35  template <typename... Args>
36  FormatString log(int verbosity, String tag, String message, Args... args) {
37  auto logAction = [this, verbosity, tag](const FormatString& fmt) {
38  String message = fmt;
39  uint64_t timestamp = _clock.get();
40  std::lock_guard<Mutex> _(_mutex);
41  for (auto& item : _sinks) {
42  if (item.first < verbosity)
43  continue;
44  item.second->log(static_cast<Verbosity>(verbosity), tag,
45  message, timestamp);
46  }
47  };
48  return std::move(FormatString(message, logAction).fillWith(args...));
49  }
50 
51  template <typename... Args>
52  FormatString logPanic(String tag, String message, Args... args) {
53  return log(PANIC, tag, message, args...);
54  }
55 
56  template <typename... Args>
57  FormatString logError(String tag, String message, Args... args) {
58  return log(ERROR, tag, message, args...);
59  }
60 
61  template <typename... Args>
62  FormatString logWarning(String tag, String message, Args... args) {
63  return log(WARNING, tag, message, args...);
64  }
65 
66  template <typename... Args>
67  FormatString logInfo(String tag, String message, Args... args) {
68  return log(INFO, tag, message, args...);
69  }
70  template <typename... Args>
71  FormatString logDebug(String tag, String message, Args... args) {
72  return log(DEBUG, tag, message, args...);
73  }
74 
75 private:
76  Mutex _mutex;
77  Clock _clock;
78  std::vector<std::pair<int, std::unique_ptr<BaseLogSink<String>>>> _sinks;
79 };
80 
81 template <class String>
82 class BaseStreamLogSink : public BaseLogSink<String> {
83 public:
84  BaseStreamLogSink(std::ostream& stream, unsigned width = 80)
85  : _stream(stream)
86  , _width(width - TIME_WIDTH - LEVEL_WIDTH - TAG_WIDTH - 13) {
87  if (_width < 0)
88  _width = 0;
89  std::string header = format("| {} | {} | {} | {} |\n")
90  << string("Time").width(TIME_WIDTH).alignLeft()
91  << string("Level").width(LEVEL_WIDTH).center()
92  << string("Tag").width(TAG_WIDTH).center()
93  << string("Message ").width(_width).center();
94  _stream << header;
95  }
96 
97  virtual void log(Verbosity verb, const String& tag, const String& message,
98  uint64_t timestamp) override {
99  static std::vector<String> levels(
100  { "panic", "error", "warning", "info", "debug" });
101  if (verb >= PANIC && verb <= DEBUG) {
102  String row = format("| {} | {} | {} | {} |\n")
103  << number(timestamp).alignRight().width(TIME_WIDTH)
104  << string(levels[verb + 3]).alignRight().width(LEVEL_WIDTH)
105  << string(tag).alignRight().width(TAG_WIDTH)
106  << string(message).alignLeft().width(_width).clip();
107  _stream << row;
108  } else {
109  String row = format("| {} | {} | {} | {} |\n")
110  << number(timestamp).alignRight().width(TIME_WIDTH)
111  << number(static_cast<int>(verb)).width(LEVEL_WIDTH)
112  << string(tag).alignRight().width(TAG_WIDTH)
113  << string(message).alignLeft().width(_width).clip();
114  _stream << row;
115  }
116  }
117 
118 private:
119  std::ostream& _stream;
120  int _width;
121 
122  static constexpr const int TIME_WIDTH = 10;
123  static constexpr const int LEVEL_WIDTH = 7;
124  static constexpr const int TAG_WIDTH = 10;
125 };
126 
127 struct DummyClock {
128  uint64_t get() { return 0; }
129 };
130 
131 struct ESP32UptimeClock {
132  uint64_t get() {
133  struct timeval t;
134  gettimeofday(&t, NULL);
135  return t.tv_sec * 1000 + t.tv_usec / 1000;
136  }
137 };
138 
139 using LogSink = BaseLogSink<std::string>;
140 using Logger = BaseLogger<std::string, std::mutex, ESP32UptimeClock>;
141 using StreamLogSink = BaseStreamLogSink<std::string>;
FormatString logPanic(const std::string &tag, const std::string &message, Args... args)
Definition: RBControl_logger.hpp:21
FormatString logInfo(const std::string &tag, const std::string &message, Args... args)
Definition: RBControl_logger.hpp:36
FormatString log(int verbosity, const std::string &tag, const std::string &message, Args... args)
Definition: RBControl_logger.hpp:16
FormatString logWarning(const std::string &tag, const std::string &message, Args... args)
Definition: RBControl_logger.hpp:31
FormatString logDebug(const std::string &tag, const std::string &message, Args... args)
Definition: RBControl_logger.hpp:41
FormatString logError(const std::string &tag, const std::string &message, Args... args)
Definition: RBControl_logger.hpp:26