]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/util/log.hh
import 15.2.0 Octopus source
[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
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///
77class 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;
83private:
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);
101public:
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///
239class logger_registry {
240 mutable std::mutex _mutex;
241 std::unordered_map<sstring, logger*> _loggers;
242public:
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
282logger_registry& global_logger_registry();
283
284enum class logger_timestamp_style {
285 none,
286 boot,
287 real,
288};
289
9f95a23c
TL
290enum class logger_ostream_type {
291 none,
292 stdout,
293 stderr,
294};
295
11fdf7f2
TL
296struct 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///
307void apply_logging_settings(const logging_settings&);
308
309/// \cond internal
310
311extern thread_local uint64_t logging_failures;
312
313sstring pretty_type_name(const std::type_info&);
314
315sstring level_name(log_level level);
316
317template <typename T>
318class logger_for : public logger {
319public:
320 logger_for() : logger(pretty_type_name(typeid(T))) {}
321};
322
323template <typename... Args>
324void
325logger::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().
336namespace std {
337std::ostream& operator<<(std::ostream&, const std::exception_ptr&);
338std::ostream& operator<<(std::ostream&, const std::exception&);
339std::ostream& operator<<(std::ostream&, const std::system_error&);
340}
341
342/// @}