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