Spicy
logger.h
1 // Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <map>
6 #include <memory>
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include <hilti/ast/node.h>
12 #include <hilti/base/util.h>
13 
15 #define HILTI_DEBUG(dbg, ...) \
16  { \
17  if ( ::hilti::logger().isEnabled(dbg) ) \
18  ::hilti::logger()._debug(dbg, __VA_ARGS__); \
19  }
20 
21 namespace hilti {
22 namespace logging {
23 
28 class DebugStream {
29 public:
33  explicit DebugStream(const std::string& name);
34  bool operator<(const DebugStream& other) const { return _id < other._id; }
35  const auto& name() const { return _name; }
36 
38  static std::vector<std::string> all();
39 
41  static const auto& streamForName(const std::string& s) { return _streams().at(s); }
42 
43 private:
44  uint64_t _id;
45  std::string _name;
46  static std::map<std::string, DebugStream>& _streams();
47 };
48 
49 namespace debug {} // namespace debug
50 
52 enum class Level { Debug, Info, Warning, Error, FatalError, InternalError };
53 
54 namespace detail {
55 constexpr util::enum_::Value<Level> Levels[] = {
56  {.value = Level::Debug, .name = "debug"},
57  {.value = Level::Info, .name = "info"},
58  {.value = Level::Warning, .name = "warning"},
59  {.value = Level::Error, .name = "error"},
60  {.value = Level::FatalError, .name = "fatal-error"},
61  {.value = Level::InternalError, .name = "internal-error"},
62 };
63 } // namespace detail
64 
65 constexpr auto to_string(Level m) { return util::enum_::to_string(m, detail::Levels); }
66 
67 namespace level {
68 constexpr auto from_string(std::string_view s) { return util::enum_::from_string<Level>(s, detail::Levels); }
69 } // namespace level
70 
72 class Stream : public std::ostream {
73 private:
74  class Buffer : public std::stringbuf {
75  public:
76  Buffer(logging::Level level);
77  Buffer(logging::DebugStream dbg);
78 
79  private:
80  int overflow(int ch) final;
81  int sync() final;
82 
83  Level _level;
84  std::optional<logging::DebugStream> _dbg;
85  std::string _buffer;
86  };
87 
88 public:
90  Stream(logging::Level level) : std::ostream(&_buf), _buf(level) {}
91 
93  Stream(logging::DebugStream dbg) : std::ostream(&_buf), _buf(std::move(dbg)) {}
94 
95 private:
96  Buffer _buf;
97 };
98 
99 } // namespace logging
100 
101 class Logger;
102 
107 inline Logger& logger();
108 
112 extern std::unique_ptr<Logger> setLogger(std::unique_ptr<Logger> logger);
113 
115 class Logger {
116 public:
117  Logger(std::ostream& output_std = std::cerr, std::ostream& output_debug = std::cerr)
118  : _output_std(output_std), _output_debug(output_debug) {}
119 
120  void log(logging::Level level, const std::string& msg, const Location& l = location::None);
121 
122  void info(const std::string& msg, const Location& l = location::None);
123  void warning(const std::string& msg, const Location& l = location::None);
124  void deprecated(const std::string& msg, const Location& l = location::None);
125  void error(const std::string& msg, const Location& l = location::None);
126  void error(const std::string& msg, const std::vector<std::string>& context, const Location& l = location::None);
127  void fatalError(const std::string& msg, const Location& l = location::None) __attribute__((noreturn));
128  void internalError(const std::string& msg, const Location& l = location::None) __attribute__((noreturn));
129 
130  void info(const std::string& msg, const Node* n) { info(msg, n->location()); }
131  void warning(const std::string& msg, const Node* n) { warning(msg, n->location()); }
132  void deprecated(const std::string& msg, const Node* n) { deprecated(msg, n->location()); }
133  void error(const std::string& msg, const Node* n) { error(msg, n->location()); }
134  void fatalError(const std::string& msg, const Node* n) __attribute__((noreturn)) { fatalError(msg, n->location()); }
135  void internalError(const std::string& msg, const Node* n) __attribute__((noreturn)) {
136  internalError(msg, n->location());
137  }
138 
140  void _debug(const logging::DebugStream& dbg, const std::string& msg, const Location& l = location::None);
141 
142  template<typename T>
143  void log(std::string msg, const std::shared_ptr<T>& n) {
144  log(msg, n->location());
145  }
146 
147  template<typename T>
148  void info(std::string msg, const std::shared_ptr<T>& n) {
149  info(msg, n->location());
150  }
151 
152  template<typename T>
153  void warning(std::string msg, const std::shared_ptr<T>& n) {
154  warning(msg, n->location());
155  }
156 
157  template<typename T>
158  void error(std::string msg, const std::shared_ptr<T>& n) {
159  error(msg, n->location());
160  }
161 
162  template<typename T>
163  void error(std::string msg, std::vector<std::string> context, const std::shared_ptr<T>& n) {
164  error(msg, context, n.location());
165  }
166 
167  template<typename R, typename T>
168  void error(Result<R> r, const std::shared_ptr<T>& n) {
169  error(r.error().description(), n.location());
170  }
171 
172  template<typename T>
173  __attribute__((noreturn)) void fatalError(std::string msg, const std::shared_ptr<T>& n) {
174  fatalError(msg, n->location());
175  }
176 
177  template<typename T>
178  __attribute__((noreturn)) void internalError(std::string msg, const std::shared_ptr<T>& n) {
179  internalError(msg, n->location());
180  }
181 
182  template<typename T>
183  void debug(const logging::DebugStream& dbg, std::string msg, const std::shared_ptr<T>& n) {
184  debug(dbg, msg, n->location());
185  }
186 
187  void debugEnable(const logging::DebugStream& dbg);
188  bool debugEnable(const std::string& dbg);
189  void debugDisable(const logging::DebugStream& dbg) { _debug_streams.erase(dbg); }
190  bool debugDisable(const std::string& dbg);
191 
192  bool isEnabled(const logging::DebugStream& dbg) { return _debug_streams.contains(dbg); }
193 
194  void debugPushIndent(const logging::DebugStream& dbg) {
195  if ( isEnabled(dbg) )
196  _debug_streams[dbg] += 1;
197  }
198 
199  void debugPopIndent(const logging::DebugStream& dbg) {
200  if ( isEnabled(dbg) )
201  _debug_streams[dbg] -= 1;
202  }
203 
204  void debugSetIndent(const logging::DebugStream& dbg, size_t indent) {
205  if ( isEnabled(dbg) )
206  _debug_streams[dbg] = indent;
207  }
208 
209  int errors() const { return _errors; }
210  int warnings() const { return _warnings; }
211 
212  void reset() { _errors = _warnings = 0; }
213 
214 protected:
215  void report(std::ostream& output, logging::Level level, size_t indent, const std::string& addl,
216  const std::string& msg, const Location& l) const;
217 
218 private:
219  friend Logger& logger(); // NOLINT
220  friend std::unique_ptr<Logger> setLogger(std::unique_ptr<Logger> logger); // NOLINT
221 
222  std::ostream& _output_std = std::cerr;
223  std::ostream& _output_debug = std::cerr;
224 
225  int _warnings = 0;
226  int _errors = 0;
227 
228  std::map<logging::DebugStream, size_t> _debug_streams;
229 
230  static std::unique_ptr<Logger> _singleton;
231 };
232 
233 inline Logger& logger() {
234  if ( ! Logger::_singleton )
235  Logger::_singleton = std::make_unique<Logger>();
236 
237  return *Logger::_singleton;
238 }
239 
240 namespace logging {
241 
247 public:
248  DebugPushIndent(const logging::DebugStream& dbg) : _dbg(dbg) { logger().debugPushIndent(_dbg); }
249  ~DebugPushIndent() { logger().debugPopIndent(_dbg); }
250 
251  DebugPushIndent() = delete;
252  DebugPushIndent(const DebugPushIndent&) = delete;
253  DebugPushIndent(DebugPushIndent&&) noexcept = delete;
254  DebugPushIndent& operator=(const DebugPushIndent&) = delete;
255  DebugPushIndent& operator=(DebugPushIndent&&) noexcept = delete;
256 
257 private:
258  const logging::DebugStream& _dbg;
259 };
260 
261 } // namespace logging
262 
263 } // namespace hilti
Definition: location.h:17
Definition: logger.h:115
void _debug(const logging::DebugStream &dbg, const std::string &msg, const Location &l=location::None)
Definition: logger.cc:136
friend Logger & logger()
Definition: logger.h:233
friend std::unique_ptr< Logger > setLogger(std::unique_ptr< Logger > logger)
Definition: node.h:240
const auto & location() const
Definition: node.h:309
Definition: logger.h:246
Definition: logger.h:28
static std::vector< std::string > all()
Definition: logger.cc:27
DebugStream(const std::string &name)
Definition: logger.cc:17
static const auto & streamForName(const std::string &s)
Definition: logger.h:41
Definition: logger.h:72
Stream(logging::Level level)
Definition: logger.h:90
Stream(logging::DebugStream dbg)
Definition: logger.h:93
Definition: result.h:71
const result::Error & error() const
Definition: result.h:140