1 | // |
2 | // Copyright(c) 2015 Gabi Melman. |
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) |
4 | |
5 | // spdlog usage example |
6 | |
7 | #include <cstdio> |
8 | #include <chrono> |
9 | |
10 | void load_levels_example(); |
11 | void stdout_logger_example(); |
12 | void basic_example(); |
13 | void rotating_example(); |
14 | void daily_example(); |
15 | void async_example(); |
16 | void binary_example(); |
17 | void vector_example(); |
18 | void stopwatch_example(); |
19 | void trace_example(); |
20 | void multi_sink_example(); |
21 | void user_defined_example(); |
22 | void err_handler_example(); |
23 | void syslog_example(); |
24 | void udp_example(); |
25 | void custom_flags_example(); |
26 | void file_events_example(); |
27 | void replace_default_logger_example(); |
28 | |
29 | #include "spdlog/spdlog.h" |
30 | #include "spdlog/cfg/env.h" // support for loading levels from the environment variable |
31 | #include "spdlog/fmt/ostr.h" // support for user defined types |
32 | |
33 | int main(int, char *[]) |
34 | { |
35 | // Log levels can be loaded from argv/env using "SPDLOG_LEVEL" |
36 | load_levels_example(); |
37 | |
38 | spdlog::info("Welcome to spdlog version {}.{}.{} !" , SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); |
39 | |
40 | spdlog::warn("Easy padding in numbers like {:08d}" , 12); |
41 | spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}" , 42); |
42 | spdlog::info("Support for floats {:03.2f}" , 1.23456); |
43 | spdlog::info("Positional args are {1} {0}.." , "too" , "supported" ); |
44 | spdlog::info("{:>8} aligned, {:<8} aligned" , "right" , "left" ); |
45 | |
46 | // Runtime log levels |
47 | spdlog::set_level(spdlog::level::info); // Set global log level to info |
48 | spdlog::debug("This message should not be displayed!" ); |
49 | spdlog::set_level(spdlog::level::trace); // Set specific logger's log level |
50 | spdlog::debug("This message should be displayed.." ); |
51 | |
52 | // Customize msg format for all loggers |
53 | spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v" ); |
54 | spdlog::info("This an info message with custom format" ); |
55 | spdlog::set_pattern("%+" ); // back to default format |
56 | spdlog::set_level(spdlog::level::info); |
57 | |
58 | // Backtrace support |
59 | // Loggers can store in a ring buffer all messages (including debug/trace) for later inspection. |
60 | // When needed, call dump_backtrace() to see what happened: |
61 | spdlog::enable_backtrace(10); // create ring buffer with capacity of 10 messages |
62 | for (int i = 0; i < 100; i++) |
63 | { |
64 | spdlog::debug("Backtrace message {}" , i); // not logged.. |
65 | } |
66 | // e.g. if some error happened: |
67 | spdlog::dump_backtrace(); // log them now! |
68 | |
69 | try |
70 | { |
71 | stdout_logger_example(); |
72 | basic_example(); |
73 | rotating_example(); |
74 | daily_example(); |
75 | async_example(); |
76 | binary_example(); |
77 | vector_example(); |
78 | multi_sink_example(); |
79 | user_defined_example(); |
80 | err_handler_example(); |
81 | trace_example(); |
82 | stopwatch_example(); |
83 | udp_example(); |
84 | custom_flags_example(); |
85 | file_events_example(); |
86 | replace_default_logger_example(); |
87 | |
88 | // Flush all *registered* loggers using a worker thread every 3 seconds. |
89 | // note: registered loggers *must* be thread safe for this to work correctly! |
90 | spdlog::flush_every(std::chrono::seconds(3)); |
91 | |
92 | // Apply some function on all registered loggers |
93 | spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example." ); }); |
94 | |
95 | // Release all spdlog resources, and drop all loggers in the registry. |
96 | // This is optional (only mandatory if using windows + async log). |
97 | spdlog::shutdown(); |
98 | } |
99 | |
100 | // Exceptions will only be thrown upon failed logger or sink construction (not during logging). |
101 | catch (const spdlog::spdlog_ex &ex) |
102 | { |
103 | std::printf("Log initialization failed: %s\n" , ex.what()); |
104 | return 1; |
105 | } |
106 | } |
107 | |
108 | #include "spdlog/sinks/stdout_color_sinks.h" |
109 | // or #include "spdlog/sinks/stdout_sinks.h" if no colors needed. |
110 | void stdout_logger_example() |
111 | { |
112 | // Create color multi threaded logger. |
113 | auto console = spdlog::stdout_color_mt("console" ); |
114 | // or for stderr: |
115 | // auto console = spdlog::stderr_color_mt("error-logger"); |
116 | } |
117 | |
118 | #include "spdlog/sinks/basic_file_sink.h" |
119 | void basic_example() |
120 | { |
121 | // Create basic file logger (not rotated). |
122 | auto my_logger = spdlog::basic_logger_mt("file_logger" , "logs/basic-log.txt" , true); |
123 | } |
124 | |
125 | #include "spdlog/sinks/rotating_file_sink.h" |
126 | void rotating_example() |
127 | { |
128 | // Create a file rotating logger with 5mb size max and 3 rotated files. |
129 | auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name" , "logs/rotating.txt" , 1048576 * 5, 3); |
130 | } |
131 | |
132 | #include "spdlog/sinks/daily_file_sink.h" |
133 | void daily_example() |
134 | { |
135 | // Create a daily logger - a new file is created every day on 2:30am. |
136 | auto daily_logger = spdlog::daily_logger_mt("daily_logger" , "logs/daily.txt" , 2, 30); |
137 | } |
138 | |
139 | #include "spdlog/cfg/env.h" |
140 | void load_levels_example() |
141 | { |
142 | // Set the log level to "info" and mylogger to "trace": |
143 | // SPDLOG_LEVEL=info,mylogger=trace && ./example |
144 | spdlog::cfg::load_env_levels(); |
145 | // or from command line: |
146 | // ./example SPDLOG_LEVEL=info,mylogger=trace |
147 | // #include "spdlog/cfg/argv.h" // for loading levels from argv |
148 | // spdlog::cfg::load_argv_levels(args, argv); |
149 | } |
150 | |
151 | #include "spdlog/async.h" |
152 | void async_example() |
153 | { |
154 | // Default thread pool settings can be modified *before* creating the async logger: |
155 | // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread. |
156 | auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger" , "logs/async_log.txt" ); |
157 | // alternatively: |
158 | // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt"); |
159 | |
160 | for (int i = 1; i < 101; ++i) |
161 | { |
162 | async_file->info("Async message #{}" , i); |
163 | } |
164 | } |
165 | |
166 | // Log binary data as hex. |
167 | // Many types of std::container<char> types can be used. |
168 | // Iterator ranges are supported too. |
169 | // Format flags: |
170 | // {:X} - print in uppercase. |
171 | // {:s} - don't separate each byte with space. |
172 | // {:p} - don't print the position on each line start. |
173 | // {:n} - don't split the output to lines. |
174 | |
175 | #include "spdlog/fmt/bin_to_hex.h" |
176 | void binary_example() |
177 | { |
178 | std::vector<char> buf(80); |
179 | for (int i = 0; i < 80; i++) |
180 | { |
181 | buf.push_back(static_cast<char>(i & 0xff)); |
182 | } |
183 | spdlog::info("Binary example: {}" , spdlog::to_hex(buf)); |
184 | spdlog::info("Another binary example:{:n}" , spdlog::to_hex(std::begin(buf), std::begin(buf) + 10)); |
185 | // more examples: |
186 | // logger->info("uppercase: {:X}", spdlog::to_hex(buf)); |
187 | // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf)); |
188 | // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf)); |
189 | // logger->info("hexdump style: {:a}", spdlog::to_hex(buf)); |
190 | // logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20)); |
191 | } |
192 | |
193 | // Log a vector of numbers |
194 | #ifndef SPDLOG_USE_STD_FORMAT |
195 | # include "spdlog/fmt/ranges.h" |
196 | void vector_example() |
197 | { |
198 | std::vector<int> vec = {1, 2, 3}; |
199 | spdlog::info("Vector example: {}" , vec); |
200 | } |
201 | |
202 | #else |
203 | void vector_example() {} |
204 | #endif |
205 | |
206 | // ! DSPDLOG_USE_STD_FORMAT |
207 | |
208 | // Compile time log levels. |
209 | // define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE) |
210 | void trace_example() |
211 | { |
212 | // trace from default logger |
213 | SPDLOG_TRACE("Some trace message.. {} ,{}" , 1, 3.23); |
214 | // debug from default logger |
215 | SPDLOG_DEBUG("Some debug message.. {} ,{}" , 1, 3.23); |
216 | |
217 | // trace from logger object |
218 | auto logger = spdlog::get("file_logger" ); |
219 | SPDLOG_LOGGER_TRACE(logger, "another trace message" ); |
220 | } |
221 | |
222 | // stopwatch example |
223 | #include "spdlog/stopwatch.h" |
224 | #include <thread> |
225 | void stopwatch_example() |
226 | { |
227 | spdlog::stopwatch sw; |
228 | std::this_thread::sleep_for(std::chrono::milliseconds(123)); |
229 | spdlog::info("Stopwatch: {} seconds" , sw); |
230 | } |
231 | |
232 | #include "spdlog/sinks/udp_sink.h" |
233 | void udp_example() |
234 | { |
235 | spdlog::sinks::udp_sink_config cfg("127.0.0.1" , 11091); |
236 | auto my_logger = spdlog::udp_logger_mt("udplog" , cfg); |
237 | my_logger->set_level(spdlog::level::debug); |
238 | my_logger->info("hello world" ); |
239 | } |
240 | |
241 | // A logger with multiple sinks (stdout and file) - each with a different format and log level. |
242 | void multi_sink_example() |
243 | { |
244 | auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); |
245 | console_sink->set_level(spdlog::level::warn); |
246 | console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v" ); |
247 | |
248 | auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt" , true); |
249 | file_sink->set_level(spdlog::level::trace); |
250 | |
251 | spdlog::logger logger("multi_sink" , {console_sink, file_sink}); |
252 | logger.set_level(spdlog::level::debug); |
253 | logger.warn("this should appear in both console and file" ); |
254 | logger.info("this message should not appear in the console, only in the file" ); |
255 | } |
256 | |
257 | // User defined types logging |
258 | struct my_type |
259 | { |
260 | int i = 0; |
261 | explicit my_type(int i) |
262 | : i(i){}; |
263 | }; |
264 | |
265 | #ifndef SPDLOG_USE_STD_FORMAT // when using fmtlib |
266 | template<> |
267 | struct fmt::formatter<my_type> : fmt::formatter<std::string> |
268 | { |
269 | auto format(my_type my, format_context &ctx) -> decltype(ctx.out()) |
270 | { |
271 | return format_to(ctx.out(), "[my_type i={}]" , my.i); |
272 | } |
273 | }; |
274 | |
275 | #else // when using std::format |
276 | template<> |
277 | struct std::formatter<my_type> : std::formatter<std::string> |
278 | { |
279 | auto format(my_type my, format_context &ctx) -> decltype(ctx.out()) |
280 | { |
281 | return format_to(ctx.out(), "[my_type i={}]" , my.i); |
282 | } |
283 | }; |
284 | #endif |
285 | |
286 | void user_defined_example() |
287 | { |
288 | spdlog::info("user defined type: {}" , my_type(14)); |
289 | } |
290 | |
291 | // Custom error handler. Will be triggered on log failure. |
292 | void err_handler_example() |
293 | { |
294 | // can be set globally or per logger(logger->set_error_handler(..)) |
295 | spdlog::set_error_handler([](const std::string &msg) { printf("*** Custom log error handler: %s ***\n" , msg.c_str()); }); |
296 | } |
297 | |
298 | // syslog example (linux/osx/freebsd) |
299 | #ifndef _WIN32 |
300 | # include "spdlog/sinks/syslog_sink.h" |
301 | void syslog_example() |
302 | { |
303 | std::string ident = "spdlog-example" ; |
304 | auto syslog_logger = spdlog::syslog_logger_mt("syslog" , ident, LOG_PID); |
305 | syslog_logger->warn("This is warning that will end up in syslog." ); |
306 | } |
307 | #endif |
308 | |
309 | // Android example. |
310 | #if defined(__ANDROID__) |
311 | # include "spdlog/sinks/android_sink.h" |
312 | void android_example() |
313 | { |
314 | std::string tag = "spdlog-android" ; |
315 | auto android_logger = spdlog::android_logger_mt("android" , tag); |
316 | android_logger->critical("Use \"adb shell logcat\" to view this message." ); |
317 | } |
318 | #endif |
319 | |
320 | // Log patterns can contain custom flags. |
321 | // this will add custom flag '%*' which will be bound to a <my_formatter_flag> instance |
322 | #include "spdlog/pattern_formatter.h" |
323 | class my_formatter_flag : public spdlog::custom_flag_formatter |
324 | { |
325 | public: |
326 | void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override |
327 | { |
328 | std::string some_txt = "custom-flag" ; |
329 | dest.append(some_txt.data(), some_txt.data() + some_txt.size()); |
330 | } |
331 | |
332 | std::unique_ptr<custom_flag_formatter> clone() const override |
333 | { |
334 | return spdlog::details::make_unique<my_formatter_flag>(); |
335 | } |
336 | }; |
337 | |
338 | void custom_flags_example() |
339 | { |
340 | |
341 | using spdlog::details::make_unique; // for pre c++14 |
342 | auto formatter = make_unique<spdlog::pattern_formatter>(); |
343 | formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v" ); |
344 | // set the new formatter using spdlog::set_formatter(formatter) or logger->set_formatter(formatter) |
345 | // spdlog::set_formatter(std::move(formatter)); |
346 | } |
347 | |
348 | void file_events_example() |
349 | { |
350 | // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications |
351 | spdlog::file_event_handlers handlers; |
352 | handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}" , filename); }; |
353 | handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { |
354 | spdlog::info("After opening {}" , filename); |
355 | fputs("After opening\n" , fstream); |
356 | }; |
357 | handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { |
358 | spdlog::info("Before closing {}" , filename); |
359 | fputs("Before closing\n" , fstream); |
360 | }; |
361 | handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}" , filename); }; |
362 | auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/events-sample.txt" , true, handlers); |
363 | spdlog::logger my_logger("some_logger" , file_sink); |
364 | my_logger.info("Some log line" ); |
365 | } |
366 | |
367 | void replace_default_logger_example() |
368 | { |
369 | // store the old logger so we don't break other examples. |
370 | auto old_logger = spdlog::default_logger(); |
371 | |
372 | auto new_logger = spdlog::basic_logger_mt("new_default_logger" , "logs/new-default-log.txt" , true); |
373 | spdlog::set_default_logger(new_logger); |
374 | spdlog::set_level(spdlog::level::info); |
375 | spdlog::debug("This message should not be displayed!" ); |
376 | spdlog::set_level(spdlog::level::trace); |
377 | spdlog::debug("This message should be displayed.." ); |
378 | |
379 | spdlog::set_default_logger(old_logger); |
380 | } |
381 | |