forked from scylladb/scylladb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlog.hh
167 lines (143 loc) · 4.71 KB
/
log.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
* Copyright (C) 2014 Cloudius Systems, Ltd.
*/
#ifndef LOG_HH_
#define LOG_HH_
#include "core/sstring.hh"
#include <unordered_map>
#include <exception>
#include <iosfwd>
#include <atomic>
#include <mutex>
#include <boost/lexical_cast.hpp>
namespace logging {
enum class log_level {
error,
warn,
info,
debug,
trace,
};
}
// Must exist logging namespace, or ADL gets confused in logger::stringer
std::ostream& operator<<(std::ostream& out, logging::log_level level);
std::istream& operator>>(std::istream& in, logging::log_level& level);
// Boost doesn't auto-deduce the existence of the streaming operators for some reason
namespace boost {
template <>
logging::log_level lexical_cast(const std::string& source);
}
namespace logging {
class logger;
class registry;
class logger {
sstring _name;
std::atomic<log_level> _level = { log_level::warn };
static std::atomic<bool> _stdout;
static std::atomic<bool> _syslog;
private:
struct stringer {
// no need for virtual dtor, since not dynamically destroyed
virtual void append(std::ostream& os) = 0;
};
template <typename Arg>
struct stringer_for final : stringer {
explicit stringer_for(const Arg& arg) : arg(arg) {}
const Arg& arg;
virtual void append(std::ostream& os) override {
os << arg;
}
};
template <typename... Args>
void do_log(log_level level, const char* fmt, Args&&... args);
template <typename Arg, typename... Args>
void do_log_step(log_level level, const char* fmt, stringer** s, size_t n, size_t idx, Arg&& arg, Args&&... args);
void do_log_step(log_level level, const char* fmt, stringer** s, size_t n, size_t idx);
void really_do_log(log_level level, const char* fmt, stringer** stringers, size_t n);
public:
explicit logger(sstring name);
logger(logger&& x);
~logger();
bool is_enabled(log_level level) const {
return level <= _level.load(std::memory_order_relaxed);
}
template <typename... Args>
void log(log_level level, const char* fmt, Args&&... args) {
if (is_enabled(level)) {
do_log(level, fmt, std::forward<Args>(args)...);
}
}
template <typename... Args>
void error(const char* fmt, Args&&... args) {
log(log_level::error, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void warn(const char* fmt, Args&&... args) {
log(log_level::warn, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void info(const char* fmt, Args&&... args) {
log(log_level::info, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void debug(const char* fmt, Args&&... args) {
log(log_level::debug, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void trace(const char* fmt, Args&&... args) {
log(log_level::trace, fmt, std::forward<Args>(args)...);
}
const sstring& name() const {
return _name;
}
log_level level() const {
return _level.load(std::memory_order_relaxed);
}
void set_level(log_level level) {
_level.store(level, std::memory_order_relaxed);
}
static void set_stdout_enabled(bool enabled);
static void set_syslog_enabled(bool enabled);
};
class registry {
mutable std::mutex _mutex;
std::unordered_map<sstring, logger*> _loggers;
public:
void set_all_loggers_level(log_level level);
log_level get_logger_level(sstring name) const;
void set_logger_level(sstring name, log_level level);
std::vector<sstring> get_all_logger_names();
void register_logger(logger* l);
void unregister_logger(logger* l);
void moved(logger* from, logger* to);
};
sstring pretty_type_name(const std::type_info&);
registry& logger_registry();
template <typename T>
class logger_for : public logger {
public:
logger_for() : logger(pretty_type_name(typeid(T))) {}
};
inline
void
logger::do_log_step(log_level level, const char* fmt, stringer** s, size_t n, size_t idx) {
really_do_log(level, fmt, s, n);
}
template <typename Arg, typename... Args>
inline
void
logger::do_log_step(log_level level, const char* fmt, stringer** s, size_t n, size_t idx, Arg&& arg, Args&&... args) {
stringer_for<Arg> sarg{arg};
s[idx] = &sarg;
do_log_step(level, fmt, s, n, idx + 1, std::forward<Args>(args)...);
}
template <typename... Args>
void
logger::do_log(log_level level, const char* fmt, Args&&... args) {
stringer* s[sizeof...(Args)];
do_log_step(level, fmt, s, sizeof...(Args), 0, std::forward<Args>(args)...);
}
}
// Pretty-printer for exceptions to be logged, e.g., std::current_exception().
std::ostream& operator<<(std::ostream&, std::exception_ptr);
#endif /* LOG_HH_ */