Scine::Core  3.0.0
Module management and core interface definitions
 All Classes Files Functions Variables Typedefs Pages
Log.h
Go to the documentation of this file.
1 
7 #ifndef INCLUDE_SCINE_UTILS_LOG_H
8 #define INCLUDE_SCINE_UTILS_LOG_H
9 
10 #include "Core/ExportControl.h"
11 #include <fstream>
12 #include <iostream>
13 #include <memory>
14 #include <string>
15 #include <unordered_map>
16 
17 namespace Scine {
18 namespace Core {
19 namespace Traits {
20 
21 template<typename>
22 struct sfinae_true : std::true_type {};
23 
24 template<typename T>
25 static auto testIsStreamWriter(int) -> sfinae_true<decltype(std::declval<T>()(std::declval<std::ostream&>()))>;
26 
27 template<typename T>
28 static auto testIsStreamWriter(long) -> std::false_type;
29 
30 template<typename T>
31 struct isStreamWriter : decltype(testIsStreamWriter<T>(0)) {};
32 
33 } // namespace Traits
34 
57 struct CORE_EXPORT Log {
60 
64  using SinkPtr = std::shared_ptr<std::ostream>;
65 
85  class CORE_EXPORT Domain {
86  public:
88  inline Domain() = default;
90  inline Domain(std::string n, SinkPtr s) {
91  sinks_.emplace(std::move(n), std::move(s));
92  }
93 
95  inline void add(std::string n, SinkPtr s) {
96  sinks_.emplace(std::move(n), std::move(s));
97  }
98 
100  inline void clear() {
101  sinks_.clear();
102  }
103 
108  inline void remove(const std::string& name) {
109  sinks_.erase(expectantFind(name));
110  }
111 
118  inline SinkPtr extract(const std::string& name) {
119  auto findIter = expectantFind(name);
120  auto ptr = std::move(findIter->second);
121  sinks_.erase(findIter);
122  return ptr;
123  }
124 
126  inline explicit operator bool() const {
127  return !sinks_.empty();
128  }
129 
138  template<typename... Args>
139  inline void printf(Args&&... args) {
140  const int sz = snprintf(NULL, 0, std::forward<Args>(args)...);
141  char* buf = new char[sz + 1];
142  snprintf(buf, sz + 1, std::forward<Args>(args)...);
143  (*this) << std::string(buf);
144  delete[] buf;
145  }
146 
152  template<typename T>
153  std::enable_if_t<Traits::isStreamWriter<T>::value, Domain&> operator<<(T&& f) {
154  for (auto& nameSinkPair : sinks_) {
155  f(*nameSinkPair.second);
156  }
157 
158  return *this;
159  }
160 
166  template<typename T>
167  std::enable_if_t<!Traits::isStreamWriter<T>::value, Domain&> operator<<(T&& t) {
168  for (auto& nameSinkPair : sinks_) {
169  *nameSinkPair.second << t;
170  }
171  return *this;
172  }
173 
195  template<typename... Args>
196  inline void lazy(Args&&... args) {
197  if (*this) {
198  sink(std::forward<Args>(args)...);
199  }
200  }
201 
203  inline void line(const std::string& s) {
204  if (*this) {
205  *this << s << Log::nl;
206  }
207  }
208 
209  private:
210  inline void sink() {
211  }
212 
213  template<typename F, typename... Args>
214  inline void sink(F&& f, Args&&... args) {
215  *this << f();
216  return sink(args...);
217  }
218 
219  using MapType = std::unordered_map<std::string, SinkPtr>;
220  using iterator = typename MapType::iterator;
221 
222  inline iterator expectantFind(const std::string& sinkName) {
223  const auto findIter = sinks_.find(sinkName);
224  if (findIter == std::end(sinks_)) {
225  throw std::out_of_range("Sink name not found");
226  }
227  return findIter;
228  }
229 
230  std::unordered_map<std::string, SinkPtr> sinks_;
231  };
232 
233  using iterator = Domain*;
234  using const_iterator = const Domain*;
236  using reference = Domain&;
237  using pointer = Domain*;
239 
243  static inline SinkPtr fileSink(const std::string& filename) {
244  return std::make_shared<std::ofstream>(filename, std::ios_base::out | std::ios_base::app);
245  }
246 
248  static inline SinkPtr coutSink() {
249  return std::make_shared<std::ostream>(std::cout.rdbuf());
250  }
251 
253  static inline SinkPtr cerrSink() {
254  return std::make_shared<std::ostream>(std::cerr.rdbuf());
255  }
256 
258  static inline Log silent() {
259  return Log{Domain(), Domain(), Domain(), Domain()};
260  }
261 
263  static inline std::ostream& nl(std::ostream& os) {
264  os << "\n";
265  return os;
266  }
267 
269  static inline std::ostream& flush(std::ostream& os) {
270  os << std::flush;
271  return os;
272  }
273 
275  static inline std::ostream& endl(std::ostream& os) {
276  os << std::endl;
277  return os;
278  }
280 
284  inline void clear() {
285  for (Domain& domain : *this) {
286  domain.clear();
287  }
288  }
289 
295  inline void sinkAllToFile(const std::string& file, std::string sinkName = "") {
296  if (sinkName.empty()) {
297  sinkName = std::to_string(std::hash<std::string>{}(file));
298  }
299 
300  auto sink = fileSink(file);
301  for (Domain& domain : *this) {
302  domain.add(sinkName, sink);
303  }
304  }
306 
309  // NOTE: Standard guarantees in-order sequential member memory layout
310  inline iterator begin() {
311  return std::addressof(debug);
312  }
313  inline iterator end() {
314  return std::addressof(output) + 1;
315  }
316  inline const_iterator begin() const {
317  return std::addressof(debug);
318  }
319  inline const_iterator end() const {
320  return std::addressof(output) + 1;
321  }
323 
326 
335  Domain warning = Domain("cerr", cerrSink());
337  Domain error = Domain("cerr", cerrSink());
339  Domain output = Domain("cout", coutSink());
341 };
342 
343 } // namespace Core
344 } // namespace Scine
345 
346 #endif
std::shared_ptr< std::ostream > SinkPtr
Type used to represent stream sinks for logging domains.
Definition: Log.h:64
void sinkAllToFile(const std::string &file, std::string sinkName="")
Add a sink to file for all domains.
Definition: Log.h:295
void printf(Args &&...args)
Formatted logging analog to pfrintf.
Definition: Log.h:139
void clear()
Add a sink to file for all domains.
Definition: Log.h:284
static SinkPtr coutSink()
Sink referring to std::cout.
Definition: Log.h:248
static SinkPtr fileSink(const std::string &filename)
Sink referring to std::cout.
Definition: Log.h:243
Multi-sink object representing a single logging domain.
Definition: Log.h:85
static std::ostream & endl(std::ostream &os)
Inserts a newline character and flushes the stream.
Definition: Log.h:275
void line(const std::string &s)
Prints a single string with a newline character.
Definition: Log.h:203
Multi-domain multi-sink logger.
Definition: Log.h:57
static SinkPtr cerrSink()
Sink referring to std::cerr.
Definition: Log.h:253
SinkPtr extract(const std::string &name)
Extracts a sink by name.
Definition: Log.h:118
static std::ostream & nl(std::ostream &os)
Inserts a newline character into the stream.
Definition: Log.h:263
void add(std::string n, SinkPtr s)
Add a sink.
Definition: Log.h:95
void clear()
Remove all sinks.
Definition: Log.h:100
Domain(std::string n, SinkPtr s)
Single-sink constructor.
Definition: Log.h:90
static Log silent()
Creates a silent Log instance (i.e. all levels are cleared)
Definition: Log.h:258
Domain debug
Non-transient debug statements.
Definition: Log.h:333
static std::ostream & flush(std::ostream &os)
Forces flush of stream.
Definition: Log.h:269
void lazy(Args &&...args)
Conditional logging with nullary callables.
Definition: Log.h:196