]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/util/log.hh
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / seastar / include / seastar / util / log.hh
CommitLineData
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
35namespace 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///
42enum class log_level {
43 error,
44 warn,
45 info,
46 debug,
47 trace,
48};
49
50std::ostream& operator<<(std::ostream& out, log_level level);
51std::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
56namespace boost {
57template<>
58seastar::log_level lexical_cast(const std::string& source);
59
60}
61
62namespace seastar {
63
64class logger;
65class logger_registry;
66
67/// \brief Logger class for stdout or syslog.
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///
77class logger {
78 sstring _name;
79 std::atomic<log_level> _level = { log_level::info };
80 static std::atomic<bool> _stdout;
81 static std::atomic<bool> _syslog;
82private:
83 struct stringer {
84 void (*append)(std::ostream& os, const void* object);
85 const void* object;
86 };
87 template <typename Arg>
88 stringer stringer_for(const Arg& arg) {
89 return stringer{
90 [] (std::ostream& os, const void* object) {
91 os << *static_cast<const std::remove_reference_t<Arg>*>(object);
92 },
93 &arg
94 };
95 };
96 template <typename... Args>
97 void do_log(log_level level, const char* fmt, Args&&... args);
98 void really_do_log(log_level level, const char* fmt, const stringer* stringers, size_t n);
99 void failed_to_log(std::exception_ptr ex);
100public:
101 explicit logger(sstring name);
102 logger(logger&& x);
103 ~logger();
104
105 bool is_shard_zero();
106
107 /// Test if desired log level is enabled
108 ///
109 /// \param level - enum level value (info|error...)
110 /// \return true if the log level has been enabled.
111 bool is_enabled(log_level level) const {
112 return __builtin_expect(level <= _level.load(std::memory_order_relaxed), false);
113 }
114
115 /// logs to desired level if enabled, otherwise we ignore the log line
116 ///
117 /// \param fmt - printf style format
118 /// \param args - args to print string
119 ///
120 template <typename... Args>
121 void log(log_level level, const char* fmt, const Args&... args) {
122 if (is_enabled(level)) {
123 try {
124 do_log(level, fmt, args...);
125 } catch (...) {
126 failed_to_log(std::current_exception());
127 }
128 }
129 }
130
131 /// Log with error tag:
132 /// ERROR %Y-%m-%d %T,%03d [shard 0] - "your msg" \n
133 ///
134 /// \param fmt - printf style format
135 /// \param args - args to print string
136 ///
137 template <typename... Args>
138 void error(const char* fmt, Args&&... args) {
139 log(log_level::error, fmt, std::forward<Args>(args)...);
140 }
141 /// Log with warning tag:
142 /// WARN %Y-%m-%d %T,%03d [shard 0] - "your msg" \n
143 ///
144 /// \param fmt - printf style format
145 /// \param args - args to print string
146 ///
147 template <typename... Args>
148 void warn(const char* fmt, Args&&... args) {
149 log(log_level::warn, fmt, std::forward<Args>(args)...);
150 }
151 /// Log with info tag:
152 /// INFO %Y-%m-%d %T,%03d [shard 0] - "your msg" \n
153 ///
154 /// \param fmt - printf style format
155 /// \param args - args to print string
156 ///
157 template <typename... Args>
158 void info(const char* fmt, Args&&... args) {
159 log(log_level::info, fmt, std::forward<Args>(args)...);
160 }
161 /// Log with info tag on shard zero only:
162 /// INFO %Y-%m-%d %T,%03d [shard 0] - "your msg" \n
163 ///
164 /// \param fmt - printf style format
165 /// \param args - args to print string
166 ///
167 template <typename... Args>
168 void info0(const char* fmt, Args&&... args) {
169 if (is_shard_zero()) {
170 log(log_level::info, fmt, std::forward<Args>(args)...);
171 }
172 }
173 /// Log with info tag:
174 /// DEBUG %Y-%m-%d %T,%03d [shard 0] - "your msg" \n
175 ///
176 /// \param fmt - printf style format
177 /// \param args - args to print string
178 ///
179 template <typename... Args>
180 void debug(const char* fmt, Args&&... args) {
181 log(log_level::debug, fmt, std::forward<Args>(args)...);
182 }
183 /// Log with trace tag:
184 /// TRACE %Y-%m-%d %T,%03d [shard 0] - "your msg" \n
185 ///
186 /// \param fmt - printf style format
187 /// \param args - args to print string
188 ///
189 template <typename... Args>
190 void trace(const char* fmt, Args&&... args) {
191 log(log_level::trace, fmt, std::forward<Args>(args)...);
192 }
193
194 /// \return name of the logger. Usually one logger per module
195 ///
196 const sstring& name() const {
197 return _name;
198 }
199
200 /// \return current log level for this logger
201 ///
202 log_level level() const {
203 return _level.load(std::memory_order_relaxed);
204 }
205
206 /// \param level - set the log level
207 ///
208 void set_level(log_level level) {
209 _level.store(level, std::memory_order_relaxed);
210 }
211
212 /// Also output to stdout. default is true
213 static void set_stdout_enabled(bool enabled);
214
215 /// Also output to syslog. default is false
216 ///
217 /// NOTE: syslog() can block, which will stall the reactor thread.
218 /// this should be rare (will have to fill the pipe buffer
219 /// before syslogd can clear it) but can happen.
220 static void set_syslog_enabled(bool enabled);
221};
222
223/// \brief used to keep a static registry of loggers
224/// since the typical use case is to do:
225/// \code {.cpp}
226/// static seastar::logger("my_module");
227/// \endcode
228/// this class is used to wrap around the static map
229/// that holds pointers to all logs
230///
231class logger_registry {
232 mutable std::mutex _mutex;
233 std::unordered_map<sstring, logger*> _loggers;
234public:
235 /// loops through all registered loggers and sets the log level
236 /// Note: this method locks
237 ///
238 /// \param level - desired level: error,info,...
239 void set_all_loggers_level(log_level level);
240
241 /// Given a name for a logger returns the log_level enum
242 /// Note: this method locks
243 ///
244 /// \return log_level for the given logger name
245 log_level get_logger_level(sstring name) const;
246
247 /// Sets the log level for a given logger
248 /// Note: this method locks
249 ///
250 /// \param name - name of logger
251 /// \param level - desired level of logging
252 void set_logger_level(sstring name, log_level level);
253
254 /// Returns a list of registered loggers
255 /// Note: this method locks
256 ///
257 /// \return all registered loggers
258 std::vector<sstring> get_all_logger_names();
259
260 /// Registers a logger with the static map
261 /// Note: this method locks
262 ///
263 void register_logger(logger* l);
264 /// Unregisters a logger with the static map
265 /// Note: this method locks
266 ///
267 void unregister_logger(logger* l);
268 /// Swaps the logger given the from->name() in the static map
269 /// Note: this method locks
270 ///
271 void moved(logger* from, logger* to);
272};
273
274logger_registry& global_logger_registry();
275
276enum class logger_timestamp_style {
277 none,
278 boot,
279 real,
280};
281
282struct logging_settings final {
283 std::unordered_map<sstring, log_level> logger_levels;
284 log_level default_level;
285 bool stdout_enabled;
286 bool syslog_enabled;
287 logger_timestamp_style stdout_timestamp_style = logger_timestamp_style::real;
288};
289
290/// Shortcut for configuring the logging system all at once.
291///
292void apply_logging_settings(const logging_settings&);
293
294/// \cond internal
295
296extern thread_local uint64_t logging_failures;
297
298sstring pretty_type_name(const std::type_info&);
299
300sstring level_name(log_level level);
301
302template <typename T>
303class logger_for : public logger {
304public:
305 logger_for() : logger(pretty_type_name(typeid(T))) {}
306};
307
308template <typename... Args>
309void
310logger::do_log(log_level level, const char* fmt, Args&&... args) {
311 [&](auto... stringers) {
312 stringer s[sizeof...(stringers)] = {stringers...};
313 this->really_do_log(level, fmt, s, sizeof...(stringers));
314 } (stringer_for<Args>(std::forward<Args>(args))...);
315}
316
317/// \endcond
318} // end seastar namespace
319
320// Pretty-printer for exceptions to be logged, e.g., std::current_exception().
321namespace std {
322std::ostream& operator<<(std::ostream&, const std::exception_ptr&);
323std::ostream& operator<<(std::ostream&, const std::exception&);
324std::ostream& operator<<(std::ostream&, const std::system_error&);
325}
326
327/// @}