README.md 12.4 KB
Newer Older
gabime's avatar
gabime committed
1 2
# spdlog

Gabi Melman's avatar
Gabi Melman committed
3
Very fast, header-only/compiled, C++ logging library. [![Build Status](https://travis-ci.org/gabime/spdlog.svg?branch=master)](https://travis-ci.org/gabime/spdlog)  [![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true)](https://ci.appveyor.com/project/gabime/spdlog)
Gabi Melman's avatar
Gabi Melman committed
4

gabime's avatar
gabime committed
5

Gabi Melman's avatar
Gabi Melman committed
6

Gabi Melman's avatar
Gabi Melman committed
7
## Install 
Gabi Melman's avatar
Gabi Melman committed
8
#### Header only version
Gabi Melman's avatar
Gabi Melman committed
9
Copy the source [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler.
Gabi Melman's avatar
Gabi Melman committed
10

Gabi Melman's avatar
Gabi Melman committed
11
#### Static lib version (recommended - much faster compile times)
Gabi Melman's avatar
Gabi Melman committed
12 13 14 15 16
```console
$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && make -j
```
Gabi Melman's avatar
Gabi Melman committed
17 18
      
   see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use.
Gabi Melman's avatar
Gabi Melman committed
19

gabime's avatar
gabime committed
20
## Platforms
Gabi Melman's avatar
Gabi Melman committed
21
 * Linux, FreeBSD, OpenBSD, Solaris, AIX
Gabi Melman's avatar
Gabi Melman committed
22
 * Windows (msvc 2013+, cygwin)
Gabi Melman's avatar
Gabi Melman committed
23
 * macOS (clang 3.5+)
Gabi Melman's avatar
Gabi Melman committed
24
 * Android
gabime's avatar
gabime committed
25

Gabi Melman's avatar
Gabi Melman committed
26 27 28 29 30 31 32
## Package managers:
* Homebrew: `brew install spdlog`
* FreeBSD:  `cd /usr/ports/devel/spdlog/ && make install clean`
* Fedora: `yum install spdlog`
* Gentoo: `emerge dev-libs/spdlog`
* Arch Linux: `yaourt -S spdlog-git`
* vcpkg: `vcpkg install spdlog`
Gabi Melman's avatar
Gabi Melman committed
33 34
* conan: `spdlog/[>=1.4.1]@bincrafters/stable`

Gabi Melman's avatar
Gabi Melman committed
35

Devansh D's avatar
Devansh D committed
36
## Features
Gabi Melman's avatar
Gabi Melman committed
37
* Very fast (see [benchmarks](#benchmarks) below).
Gabi Melman's avatar
Gabi Melman committed
38
* Headers only, just copy and use. Or use as a compiled library.
Gabi Melman's avatar
Gabi Melman committed
39
* Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library.
Gabi Melman's avatar
Gabi Melman committed
40
* **New!** [Backtrace](#backtrace-support) support - store debug or other messages in a ring buffer and display later on demand.
gabime's avatar
gabime committed
41
* Fast asynchronous mode (optional)
gabime's avatar
gabime committed
42 43 44 45 46
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
* Multi/Single threaded loggers.
* Various log targets:
    * Rotating log files.
    * Daily log files.
Gabi Melman's avatar
Gabi Melman committed
47
    * Console logging (colors supported).
Gabi Melman's avatar
Gabi Melman committed
48
    * syslog.
Gabi Melman's avatar
Gabi Melman committed
49
    * Windows debugger (```OutputDebugString(..)```)
gabime's avatar
gabime committed
50 51 52
    * Easily extendable with custom log targets  (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface).
* Severity based filtering - threshold levels can be modified in runtime as well as in compile time.

Gabi Melman's avatar
Gabi Melman committed
53
 
Gabi Melman's avatar
Gabi Melman committed
54
## Usage samples
Gabi Melman's avatar
Gabi Melman committed
55

Gabi Melman's avatar
Gabi Melman committed
56 57 58
#### Basic usage
```c++
#include "spdlog/spdlog.h"
Martin Krammer's avatar
Martin Krammer committed
59 60
#include "spdlog/sinks/basic_file_sink.h"

Gabi Melman's avatar
Gabi Melman committed
61 62 63 64 65 66 67 68 69 70 71
int main() 
{
    spdlog::info("Welcome to spdlog!");
    spdlog::error("Some error message with arg: {}", 1);
    
    spdlog::warn("Easy padding in numbers like {:08d}", 12);
    spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
    spdlog::info("Support for floats {:03.2f}", 1.23456);
    spdlog::info("Positional args are {1} {0}..", "too", "supported");
    spdlog::info("{:<30}", "left aligned");
    
Gabi Melman's avatar
Gabi Melman committed
72
    spdlog::set_level(spdlog::level::debug); // Set global log level to debug
Gabi Melman's avatar
Gabi Melman committed
73 74 75 76 77 78 79 80 81
    spdlog::debug("This message should be displayed..");    
    
    // change log pattern
    spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
    
    // Compile time log levels
    // define SPDLOG_ACTIVE_LEVEL to desired level
    SPDLOG_TRACE("Some trace message with param {}", {});
    SPDLOG_DEBUG("Some debug message");
Gabi Melman's avatar
Gabi Melman committed
82 83 84 85
    
    // Set the default logger to file logger
    auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
    spdlog::set_default_logger(file_logger);            
Gabi Melman's avatar
Gabi Melman committed
86 87 88
}
```
#### create stdout/stderr logger object
gabime's avatar
gabime committed
89
```c++
gabime's avatar
gabime committed
90
#include "spdlog/spdlog.h"
Gabi Melman's avatar
Gabi Melman committed
91
#include "spdlog/sinks/stdout_color_sinks.h"
gabime's avatar
gabime committed
92
void stdout_example()
Gabi Melman's avatar
Gabi Melman committed
93
{
gabime's avatar
gabime committed
94
    // create color multi threaded logger
Gabi Melman's avatar
Gabi Melman committed
95 96
    auto console = spdlog::stdout_color_mt("console");    
    auto err_logger = spdlog::stderr_color_mt("stderr");    
gabime's avatar
gabime committed
97 98
    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}
Gabi Melman's avatar
Gabi Melman committed
99
```
Gabi Melman's avatar
Gabi Melman committed
100
---
Gabi Melman's avatar
Gabi Melman committed
101
#### Basic file logger
Gabi Melman's avatar
Gabi Melman committed
102
```c++
gabime's avatar
gabime committed
103 104 105 106
#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{
    try 
Gabi Melman's avatar
Gabi Melman committed
107
    {
gabime's avatar
gabime committed
108
        auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
Gabi Melman's avatar
Gabi Melman committed
109
    }
gabime's avatar
gabime committed
110
    catch (const spdlog::spdlog_ex &ex)
Gabi Melman's avatar
Gabi Melman committed
111 112 113
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
    }
gabime's avatar
gabime committed
114
}
Gabi Melman's avatar
Gabi Melman committed
115
```
Gabi Melman's avatar
Gabi Melman committed
116
---
Gabi Melman's avatar
Gabi Melman committed
117
#### Rotating files
Gabi Melman's avatar
Gabi Melman committed
118
```c++
gabime's avatar
gabime committed
119 120 121 122 123 124
#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5mb size max and 3 rotated files
    auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
}
Gabi Melman's avatar
Gabi Melman committed
125
```
126

Gabi Melman's avatar
Gabi Melman committed
127
---
Gabi Melman's avatar
Gabi Melman committed
128
#### Daily files
Gabi Melman's avatar
Gabi Melman committed
129
```c++
gabime's avatar
gabime committed
130 131 132 133 134 135 136 137

#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
    // Create a daily logger - a new file is created every day on 2:30am
    auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

Gabi Melman's avatar
Gabi Melman committed
138
```
139 140

---
Gabi Melman's avatar
Gabi Melman committed
141
#### Backtrace support
142
```c++
Gabi Melman's avatar
Gabi Melman committed
143
// Loggers can store in a ring buffer all messages (including debug/trace) and display later on demand.
Gabi Melman's avatar
Gabi Melman committed
144
// When needed, call dump_backtrace() to see them
Gabi Melman's avatar
Gabi Melman committed
145
spdlog::enable_backtrace(32); // create ring buffer with capacity of 32  messages
Gabi Melman's avatar
Gabi Melman committed
146
// or my_logger->enable_backtrace(32)..
Gabi Melman's avatar
Gabi Melman committed
147
for(int i = 0; i < 100; i++)
148
{
Gabi Melman's avatar
Gabi Melman committed
149
  spdlog::debug("Backtrace message {}", i); // not logged yet..
150
}
Gabi Melman's avatar
Gabi Melman committed
151
// e.g. if some error happened:
Gabi Melman's avatar
Gabi Melman committed
152
spdlog::dump_backtrace(); // log them now! show the last 32 messages
Gabi Melman's avatar
Gabi Melman committed
153 154

// or my_logger->dump_backtrace(32)..
155 156 157
```

---
gabime's avatar
gabime committed
158
#### Periodic flush
159
```c++
160 161 162 163 164 165
// periodically flush all *registered* loggers every 3 seconds:
// warning: only use if all your loggers are thread safe!
spdlog::flush_every(std::chrono::seconds(3));

```

gabime's avatar
gabime committed
166
---
Gabi Melman's avatar
Gabi Melman committed
167
#### Log binary data in hex
gabime's avatar
gabime committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
```c++
// many types of std::container<char> types can be used.
// ranges are supported too.
// format flags:
// {:X} - print in uppercase.
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines.

#include "spdlog/fmt/bin_to_hex.h"

void binary_example()
{
    auto console = spdlog::get("console");
    std::array<char, 80> buf;
    console->info("Binary example: {}", spdlog::to_hex(buf));
    console->info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
    // more examples:
    // logger->info("uppercase: {:X}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
}

```
gabime's avatar
gabime committed
192

Gabi Melman's avatar
Gabi Melman committed
193
---
gabime's avatar
gabime committed
194
#### Logger with multi sinks - each with different format and log level
Gabi Melman's avatar
Gabi Melman committed
195 196
```c++

Gabi Melman's avatar
Gabi Melman committed
197 198
// create logger with 2 targets with different log levels and formats.
// the console will show only warnings or errors, while the file will log all.
gabime's avatar
gabime committed
199
void multi_sink_example()
Gabi Melman's avatar
Gabi Melman committed
200
{
gabime's avatar
gabime committed
201 202 203
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);
    console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
gabime's avatar
gabime committed
204

gabime's avatar
gabime committed
205 206
    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);
Gabi Melman's avatar
Gabi Melman committed
207

gabime's avatar
gabime committed
208 209 210 211 212
    spdlog::logger logger("multi_sink", {console_sink, file_sink});
    logger.set_level(spdlog::level::debug);
    logger.warn("this should appear in both console and file");
    logger.info("this message should not appear in the console, only in the file");
}
Gabi Melman's avatar
Gabi Melman committed
213
```
gabime's avatar
gabime committed
214 215

---
gabime's avatar
gabime committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
#### Asynchronous logging
```c++
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
void async_example()
{
    // default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread.
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");   
}

```

---
#### Asynchronous logger with multi sinks  
gabime's avatar
gabime committed
233
```c++
gabime's avatar
gabime committed
234 235 236
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"

gabime's avatar
gabime committed
237 238 239 240 241 242 243 244 245 246 247
void multi_sink_example2()
{
    spdlog::init_thread_pool(8192, 1);
    auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
    auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
    std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink};
    auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
    spdlog::register_logger(logger);
}
```
 
Gabi Melman's avatar
Gabi Melman committed
248
---
Gabi Melman's avatar
Gabi Melman committed
249
#### User defined types
Gabi Melman's avatar
Gabi Melman committed
250
```c++
gabime's avatar
gabime committed
251
// user defined types logging by implementing operator<<
gabime's avatar
gabime committed
252
#include "spdlog/fmt/ostr.h" // must be included
gabime's avatar
gabime committed
253 254 255 256
struct my_type
{
    int i;
    template<typename OStream>
Gabi Melman's avatar
Gabi Melman committed
257
    friend OStream &operator<<(OStream &os, const my_type &c)
gabime's avatar
gabime committed
258
    {
Gabi Melman's avatar
Gabi Melman committed
259
        return os << "[my_type i=" << c.i << "]";
gabime's avatar
gabime committed
260
    }
gabime's avatar
gabime committed
261 262 263 264
};

void user_defined_example()
{
gabime's avatar
gabime committed
265
    spdlog::get("console")->info("user defined type: {}", my_type{14});
gabime's avatar
gabime committed
266 267
}

Gabi Melman's avatar
Gabi Melman committed
268
```
Gabi Melman's avatar
Gabi Melman committed
269
---
Gabi Melman's avatar
Gabi Melman committed
270 271
#### Custom error handler
```c++
gabime's avatar
gabime committed
272
void err_handler_example()
Gabi Melman's avatar
Gabi Melman committed
273
{
gabime's avatar
gabime committed
274 275 276 277 278
    // can be set globally or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
    spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}

Gabi Melman's avatar
Gabi Melman committed
279
```
Gabi Melman's avatar
Gabi Melman committed
280
---
Gabi Melman's avatar
Gabi Melman committed
281
#### syslog 
Gabi Melman's avatar
Gabi Melman committed
282
```c++
gabime's avatar
gabime committed
283 284 285 286
#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{
    std::string ident = "spdlog-example";
Gabi Melman's avatar
Gabi Melman committed
287
    auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
gabime's avatar
gabime committed
288
    syslog_logger->warn("This is warning that will end up in syslog.");
gabime's avatar
gabime committed
289
}
Gabi Melman's avatar
Gabi Melman committed
290
```
Gabi Melman's avatar
Gabi Melman committed
291
---
Gabi Melman's avatar
Gabi Melman committed
292 293
#### Android example 
```c++
294
#include "spdlog/sinks/android_sink.h"
gabime's avatar
gabime committed
295 296 297
void android_example()
{
    std::string tag = "spdlog-android";
298
    auto android_logger = spdlog::android_logger_mt("android", tag);
gabime's avatar
gabime committed
299 300
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
}
gabime's avatar
gabime committed
301 302
```

Gabi Melman's avatar
Gabi Melman committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
## Benchmarks

Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz

#### Synchronous mode
```
[info] **************************************************************
[info] Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st         Elapsed: 0.17 secs        5,777,626/sec
[info] rotating_st      Elapsed: 0.18 secs        5,475,894/sec
[info] daily_st         Elapsed: 0.20 secs        5,062,659/sec
[info] empty_logger     Elapsed: 0.07 secs       14,127,300/sec
[info] **************************************************************
[info] C-string (400 bytes). Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st         Elapsed: 0.41 secs        2,412,483/sec
[info] rotating_st      Elapsed: 0.72 secs        1,389,196/sec
[info] daily_st         Elapsed: 0.42 secs        2,393,298/sec
[info] null_st          Elapsed: 0.04 secs       27,446,957/sec
[info] **************************************************************
[info] 10 threads sharing same logger, 1,000,000 iterations
[info] **************************************************************
[info] basic_mt         Elapsed: 0.60 secs        1,659,613/sec
[info] rotating_mt      Elapsed: 0.62 secs        1,612,493/sec
[info] daily_mt         Elapsed: 0.61 secs        1,638,305/sec
[info] null_mt          Elapsed: 0.16 secs        6,272,758/sec
```
#### ASynchronous mode
Gabi Melman's avatar
Gabi Melman committed
332
```
Gabi Melman's avatar
Gabi Melman committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
[info] -------------------------------------------------
[info] Messages     : 1,000,000
[info] Threads      : 10
[info] Queue        : 8,192 slots
[info] Queue memory : 8,192 x 272 = 2,176 KB 
[info] Total iters  : 3
[info] -------------------------------------------------
[info] 
[info] *********************************
[info] Queue Overflow Policy: block
[info] *********************************
[info] Elapsed: 1.70784 secs     585,535/sec
[info] Elapsed: 1.69805 secs     588,910/sec
[info] Elapsed: 1.7026 secs      587,337/sec
[info] 
[info] *********************************
[info] Queue Overflow Policy: overrun
[info] *********************************
[info] Elapsed: 0.372816 secs    2,682,285/sec
[info] Elapsed: 0.379758 secs    2,633,255/sec
[info] Elapsed: 0.373532 secs    2,677,147/sec

Gabi Melman's avatar
Gabi Melman committed
355 356
```

gabime's avatar
gabime committed
357 358
## Documentation
Documentation can be found in the [wiki](https://github.com/gabime/spdlog/wiki/1.-QuickStart) pages.