]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* |
2 | * This file is open source software, licensed to you under the terms | |
3 | * of the Apache License, Version 2.0 (the "License"). See the NOTICE file | |
4 | * distributed with this work for additional information regarding copyright | |
5 | * ownership. You may not use this file except in compliance with the License. | |
6 | * | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, | |
12 | * software distributed under the License is distributed on an | |
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | * KIND, either express or implied. See the License for the | |
15 | * specific language governing permissions and limitations | |
16 | * under the License. | |
17 | */ | |
18 | /* | |
19 | * Copyright (C) 2015 Cloudius Systems, Ltd. | |
20 | */ | |
21 | #pragma once | |
22 | ||
23 | #include <seastar/core/sstring.hh> | |
24 | #include <unordered_map> | |
25 | #include <exception> | |
26 | #include <iosfwd> | |
27 | #include <atomic> | |
28 | #include <mutex> | |
29 | #include <boost/lexical_cast.hpp> | |
30 | ||
31 | ||
32 | /// \addtogroup logging | |
33 | /// @{ | |
34 | ||
35 | namespace seastar { | |
36 | ||
37 | /// \brief log level used with \see {logger} | |
38 | /// used with the logger.do_log method. | |
39 | /// Levels are in increasing order. That is if you want to see debug(3) logs you | |
40 | /// will also see error(0), warn(1), info(2). | |
41 | /// | |
42 | enum class log_level { | |
43 | error, | |
44 | warn, | |
45 | info, | |
46 | debug, | |
47 | trace, | |
48 | }; | |
49 | ||
50 | std::ostream& operator<<(std::ostream& out, log_level level); | |
51 | std::istream& operator>>(std::istream& in, log_level& level); | |
52 | } | |
53 | ||
54 | // Boost doesn't auto-deduce the existence of the streaming operators for some reason | |
55 | ||
56 | namespace boost { | |
57 | template<> | |
58 | seastar::log_level lexical_cast(const std::string& source); | |
59 | ||
60 | } | |
61 | ||
62 | namespace seastar { | |
63 | ||
64 | class logger; | |
65 | class logger_registry; | |
66 | ||
9f95a23c | 67 | /// \brief Logger class for ostream or syslog. |
11fdf7f2 TL |
68 | /// |
69 | /// Java style api for logging. | |
70 | /// \code {.cpp} | |
71 | /// static seastar::logger logger("lsa-api"); | |
72 | /// logger.info("Triggering compaction"); | |
73 | /// \endcode | |
74 | /// The output format is: (depending on level) | |
75 | /// DEBUG %Y-%m-%d %T,%03d [shard 0] - "your msg" \n | |
76 | /// | |
77 | class logger { | |
78 | sstring _name; | |
79 | std::atomic<log_level> _level = { log_level::info }; | |
9f95a23c TL |
80 | static std::ostream* _out; |
81 | static std::atomic<bool> _ostream; | |
11fdf7f2 TL |
82 | static std::atomic<bool> _syslog; |
83 | private: | |
84 | struct stringer { | |
85 | void (*append)(std::ostream& os, const void* object); | |
86 | const void* object; | |
87 | }; | |
88 | template <typename Arg> | |
89 | stringer stringer_for(const Arg& arg) { | |
90 | return stringer{ | |
91 | [] (std::ostream& os, const void* object) { | |
92 | os << *static_cast<const std::remove_reference_t<Arg>*>(object); | |
93 | }, | |
94 | &arg | |
95 | }; | |
96 | }; | |
97 | template <typename... Args> | |
98 | void do_log(log_level level, const char* fmt, Args&&... args); | |
99 | void really_do_log(log_level level, const char* fmt, const stringer* stringers, size_t n); | |
100 | void failed_to_log(std::exception_ptr ex); | |
101 | public: | |
102 | explicit logger(sstring name); | |
103 | logger(logger&& x); | |
104 | ~logger(); | |
105 | ||
106 | bool is_shard_zero(); | |
107 | ||
108 | /// Test if desired log level is enabled | |
109 | /// | |
110 | /// \param level - enum level value (info|error...) | |
111 | /// \return true if the log level has been enabled. | |
112 | bool is_enabled(log_level level) const { | |
113 | return __builtin_expect(level <= _level.load(std::memory_order_relaxed), false); | |
114 | } | |
115 | ||
116 | /// logs to desired level if enabled, otherwise we ignore the log line | |
117 | /// | |
118 | /// \param fmt - printf style format | |
119 | /// \param args - args to print string | |
120 | /// | |
121 | template <typename... Args> | |
122 | void log(log_level level, const char* fmt, const Args&... args) { | |
123 | if (is_enabled(level)) { | |
124 | try { | |
125 | do_log(level, fmt, args...); | |
126 | } catch (...) { | |
127 | failed_to_log(std::current_exception()); | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | /// Log with error tag: | |
133 | /// ERROR %Y-%m-%d %T,%03d [shard 0] - "your msg" \n | |
134 | /// | |
135 | /// \param fmt - printf style format | |
136 | /// \param args - args to print string | |
137 | /// | |
138 | template <typename... Args> | |
139 | void error(const char* fmt, Args&&... args) { | |
140 | log(log_level::error, fmt, std::forward<Args>(args)...); | |
141 | } | |
142 | /// Log with warning tag: | |
143 | /// WARN %Y-%m-%d %T,%03d [shard 0] - "your msg" \n | |
144 | /// | |
145 | /// \param fmt - printf style format | |
146 | /// \param args - args to print string | |
147 | /// | |
148 | template <typename... Args> | |
149 | void warn(const char* fmt, Args&&... args) { | |
150 | log(log_level::warn, fmt, std::forward<Args>(args)...); | |
151 | } | |
152 | /// Log with info tag: | |
153 | /// INFO %Y-%m-%d %T,%03d [shard 0] - "your msg" \n | |
154 | /// | |
155 | /// \param fmt - printf style format | |
156 | /// \param args - args to print string | |
157 | /// | |
158 | template <typename... Args> | |
159 | void info(const char* fmt, Args&&... args) { | |
160 | log(log_level::info, fmt, std::forward<Args>(args)...); | |
161 | } | |
162 | /// Log with info tag on shard zero only: | |
163 | /// INFO %Y-%m-%d %T,%03d [shard 0] - "your msg" \n | |
164 | /// | |
165 | /// \param fmt - printf style format | |
166 | /// \param args - args to print string | |
167 | /// | |
168 | template <typename... Args> | |
169 | void info0(const char* fmt, Args&&... args) { | |
170 | if (is_shard_zero()) { | |
171 | log(log_level::info, fmt, std::forward<Args>(args)...); | |
172 | } | |
173 | } | |
174 | /// Log with info tag: | |
175 | /// DEBUG %Y-%m-%d %T,%03d [shard 0] - "your msg" \n | |
176 | /// | |
177 | /// \param fmt - printf style format | |
178 | /// \param args - args to print string | |
179 | /// | |
180 | template <typename... Args> | |
181 | void debug(const char* fmt, Args&&... args) { | |
182 | log(log_level::debug, fmt, std::forward<Args>(args)...); | |
183 | } | |
184 | /// Log with trace tag: | |
185 | /// TRACE %Y-%m-%d %T,%03d [shard 0] - "your msg" \n | |
186 | /// | |
187 | /// \param fmt - printf style format | |
188 | /// \param args - args to print string | |
189 | /// | |
190 | template <typename... Args> | |
191 | void trace(const char* fmt, Args&&... args) { | |
192 | log(log_level::trace, fmt, std::forward<Args>(args)...); | |
193 | } | |
194 | ||
195 | /// \return name of the logger. Usually one logger per module | |
196 | /// | |
197 | const sstring& name() const { | |
198 | return _name; | |
199 | } | |
200 | ||
201 | /// \return current log level for this logger | |
202 | /// | |
203 | log_level level() const { | |
204 | return _level.load(std::memory_order_relaxed); | |
205 | } | |
206 | ||
207 | /// \param level - set the log level | |
208 | /// | |
209 | void set_level(log_level level) { | |
210 | _level.store(level, std::memory_order_relaxed); | |
211 | } | |
212 | ||
9f95a23c TL |
213 | /// Set output stream, default is std::cerr |
214 | static void set_ostream(std::ostream& out); | |
215 | ||
216 | /// Also output to ostream. default is true | |
217 | static void set_ostream_enabled(bool enabled); | |
218 | ||
11fdf7f2 | 219 | /// Also output to stdout. default is true |
9f95a23c | 220 | [[deprecated("Use set_ostream_enabled instead")]] |
11fdf7f2 TL |
221 | static void set_stdout_enabled(bool enabled); |
222 | ||
223 | /// Also output to syslog. default is false | |
224 | /// | |
225 | /// NOTE: syslog() can block, which will stall the reactor thread. | |
226 | /// this should be rare (will have to fill the pipe buffer | |
227 | /// before syslogd can clear it) but can happen. | |
228 | static void set_syslog_enabled(bool enabled); | |
229 | }; | |
230 | ||
231 | /// \brief used to keep a static registry of loggers | |
232 | /// since the typical use case is to do: | |
233 | /// \code {.cpp} | |
234 | /// static seastar::logger("my_module"); | |
235 | /// \endcode | |
236 | /// this class is used to wrap around the static map | |
237 | /// that holds pointers to all logs | |
238 | /// | |
239 | class logger_registry { | |
240 | mutable std::mutex _mutex; | |
241 | std::unordered_map<sstring, logger*> _loggers; | |
242 | public: | |
243 | /// loops through all registered loggers and sets the log level | |
244 | /// Note: this method locks | |
245 | /// | |
246 | /// \param level - desired level: error,info,... | |
247 | void set_all_loggers_level(log_level level); | |
248 | ||
249 | /// Given a name for a logger returns the log_level enum | |
250 | /// Note: this method locks | |
251 | /// | |
252 | /// \return log_level for the given logger name | |
253 | log_level get_logger_level(sstring name) const; | |
254 | ||
255 | /// Sets the log level for a given logger | |
256 | /// Note: this method locks | |
257 | /// | |
258 | /// \param name - name of logger | |
259 | /// \param level - desired level of logging | |
260 | void set_logger_level(sstring name, log_level level); | |
261 | ||
262 | /// Returns a list of registered loggers | |
263 | /// Note: this method locks | |
264 | /// | |
265 | /// \return all registered loggers | |
266 | std::vector<sstring> get_all_logger_names(); | |
267 | ||
268 | /// Registers a logger with the static map | |
269 | /// Note: this method locks | |
270 | /// | |
271 | void register_logger(logger* l); | |
272 | /// Unregisters a logger with the static map | |
273 | /// Note: this method locks | |
274 | /// | |
275 | void unregister_logger(logger* l); | |
276 | /// Swaps the logger given the from->name() in the static map | |
277 | /// Note: this method locks | |
278 | /// | |
279 | void moved(logger* from, logger* to); | |
280 | }; | |
281 | ||
282 | logger_registry& global_logger_registry(); | |
283 | ||
284 | enum class logger_timestamp_style { | |
285 | none, | |
286 | boot, | |
287 | real, | |
288 | }; | |
289 | ||
9f95a23c TL |
290 | enum class logger_ostream_type { |
291 | none, | |
292 | stdout, | |
293 | stderr, | |
294 | }; | |
295 | ||
11fdf7f2 TL |
296 | struct logging_settings final { |
297 | std::unordered_map<sstring, log_level> logger_levels; | |
298 | log_level default_level; | |
299 | bool stdout_enabled; | |
300 | bool syslog_enabled; | |
301 | logger_timestamp_style stdout_timestamp_style = logger_timestamp_style::real; | |
9f95a23c | 302 | logger_ostream_type logger_ostream = logger_ostream_type::stderr; |
11fdf7f2 TL |
303 | }; |
304 | ||
305 | /// Shortcut for configuring the logging system all at once. | |
306 | /// | |
307 | void apply_logging_settings(const logging_settings&); | |
308 | ||
309 | /// \cond internal | |
310 | ||
311 | extern thread_local uint64_t logging_failures; | |
312 | ||
313 | sstring pretty_type_name(const std::type_info&); | |
314 | ||
315 | sstring level_name(log_level level); | |
316 | ||
317 | template <typename T> | |
318 | class logger_for : public logger { | |
319 | public: | |
320 | logger_for() : logger(pretty_type_name(typeid(T))) {} | |
321 | }; | |
322 | ||
323 | template <typename... Args> | |
324 | void | |
325 | logger::do_log(log_level level, const char* fmt, Args&&... args) { | |
326 | [&](auto... stringers) { | |
327 | stringer s[sizeof...(stringers)] = {stringers...}; | |
328 | this->really_do_log(level, fmt, s, sizeof...(stringers)); | |
329 | } (stringer_for<Args>(std::forward<Args>(args))...); | |
330 | } | |
331 | ||
332 | /// \endcond | |
333 | } // end seastar namespace | |
334 | ||
335 | // Pretty-printer for exceptions to be logged, e.g., std::current_exception(). | |
336 | namespace std { | |
337 | std::ostream& operator<<(std::ostream&, const std::exception_ptr&); | |
338 | std::ostream& operator<<(std::ostream&, const std::exception&); | |
339 | std::ostream& operator<<(std::ostream&, const std::system_error&); | |
340 | } | |
341 | ||
342 | /// @} |