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

Gabi Melman's avatar
Gabi Melman committed
3 4
Very fast, header only, 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)

gabime's avatar
gabime committed
5 6

## Install
Gabi Melman's avatar
Gabi Melman committed
7
#### Just copy the headers:
8

Gabi Melman's avatar
Gabi Melman committed
9 10
* Copy the source [folder](https://github.com/gabime/spdlog/tree/master/include/spdlog) to your build tree and use a C++11 compiler.

Gabi Melman's avatar
Gabi Melman committed
11
#### Or use your favorite package manager:
Gabi Melman's avatar
Gabi Melman committed
12

13 14
* Ubuntu: `apt-get install libspdlog-dev`
* Homebrew: `brew install spdlog`
Gabi Melman's avatar
Gabi Melman committed
15
* FreeBSD:  `cd /usr/ports/devel/spdlog/ && make install clean`
16
* Fedora: `yum install spdlog`
17
* Gentoo: `emerge dev-libs/spdlog`
Vitor Alves's avatar
Vitor Alves committed
18
* Arch Linux: `yaourt -S spdlog-git`
19 20
* vcpkg: `vcpkg install spdlog`
 
gabime's avatar
gabime committed
21 22

## Platforms
Gabi Melman's avatar
Gabi Melman committed
23
 * Linux, FreeBSD, Solaris
Gabi Melman's avatar
Gabi Melman committed
24
 * Windows (vc 2013+, cygwin/mingw)
Gabi Melman's avatar
Gabi Melman committed
25
 * Mac OSX (clang 3.5+)
Gabi Melman's avatar
Gabi Melman committed
26
 * Android
gabime's avatar
gabime committed
27

Devansh D's avatar
Devansh D committed
28
## Features
gabime's avatar
gabime committed
29
* Very fast - performance is the primary goal (see [benchmarks](#benchmarks) below).
Gabi Melman's avatar
Gabi Melman committed
30
* Headers only, just copy and use.
Gabi Melman's avatar
Gabi Melman committed
31
* Feature rich [call style](#usage-example) using the excellent [fmt](https://github.com/fmtlib/fmt) library.
Gabi Melman's avatar
Gabi Melman committed
32
* Optional printf syntax support.
gabime's avatar
gabime committed
33 34
* Extremely fast asynchronous mode (optional) - using lockfree queues and other tricks to reach millions of calls/sec.
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
Asit Kumar Dhal's avatar
Asit Kumar Dhal committed
35
* Conditional Logging
gabime's avatar
gabime committed
36 37 38 39
* Multi/Single threaded loggers.
* Various log targets:
    * Rotating log files.
    * Daily log files.
Gabi Melman's avatar
Gabi Melman committed
40
    * Console logging (colors supported).
Gabi Melman's avatar
Gabi Melman committed
41
    * syslog.
Gabi Melman's avatar
Gabi Melman committed
42
    * Windows debugger (```OutputDebugString(..)```)
gabime's avatar
gabime committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
    * 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.



## Benchmarks

Below are some [benchmarks](bench) comparing popular log libraries under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz

#### Synchronous mode
Time needed to log 1,000,000 lines in synchronous mode (in seconds, the best of 3 runs):

|threads|boost log 1.54|glog   |easylogging |spdlog|
|-------|:-------:|:-----:|----------:|------:|
|1|       4.169s  |1.066s |0.975s     |0.302s|
|10|     6.180s   |3.032s |2.857s     |0.968s|
|100|     5.981s  |1.139s |4.512s     |0.497s|


#### Asynchronous mode
Time needed to log 1,000,000 lines in asynchronous mode, i.e. the time it takes to put them in the async queue (in seconds, the best of 3 runs):

|threads|g2log <sup>async logger</sup>   |spdlog <sup>async mode</sup>|
|:-------|:-----:|-------------------------:|
|1|       1.850s |0.216s |
|10|      0.943s  |0.173s|
|100|      0.959s |0.202s|




## Usage Example
```c++
Gabi Melman's avatar
Gabi Melman committed
76

gabime's avatar
gabime committed
77 78
#include "spdlog/spdlog.h"

gabime's avatar
gabime committed
79 80 81 82 83 84 85 86 87
#include <iostream>
#include <memory>

void async_example();
void syslog_example();
void user_defined_example();
void err_handler_example();

namespace spd = spdlog;
Gabi Melman's avatar
Gabi Melman committed
88 89 90 91 92 93 94 95 96
int main(int, char*[])
{
    try
    {
        // Console logger with color
        auto console = spd::stdout_color_mt("console");
        console->info("Welcome to spdlog!");
        console->error("Some error message with arg{}..", 1);

Asit Kumar Dhal's avatar
Asit Kumar Dhal committed
97 98 99 100
	// Conditional logging example
        auto i = 2;
        console->warn_if(i != 0, "an important message");

Gabi Melman's avatar
Gabi Melman committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
        // Formatting examples
        console->warn("Easy padding in numbers like {:08d}", 12);
        console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
        console->info("Support for floats {:03.2f}", 1.23456);
        console->info("Positional args are {1} {0}..", "too", "supported");
        console->info("{:<30}", "left aligned");
        

        spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
        
        // Create basic file logger (not rotated)
        auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic.txt");
        my_logger->info("Some log message");

        // Create a file rotating logger with 5mb size max and 3 rotated files
        auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/mylogfile", 1048576 * 5, 3);
        for (int i = 0; i < 10; ++i)
            rotating_logger->info("{} * {} equals {:>10}", i, i, i*i);

        // Create a daily logger - a new file is created every day on 2:30am
        auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily", 2, 30);
        // trigger flush if the log severity is error or higher
        daily_logger->flush_on(spd::level::err);
        daily_logger->info(123.44);

        // Customize msg format for all messages
        spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
        rotating_logger->info("This is another message with custom format");


Gabi Melman's avatar
Gabi Melman committed
131 132
        // Runtime log levels
	spd::set_level(spd::level::info); //Set global log level to info
Berkus Decker's avatar
Berkus Decker committed
133
	console->debug("This message should not be displayed!");
Gabi Melman's avatar
Gabi Melman committed
134
	console->set_level(spd::level::debug); // Set specific logger's log level
Berkus Decker's avatar
Berkus Decker committed
135
	console->debug("This message should be displayed..");
Gabi Melman's avatar
Gabi Melman committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

        // Compile time log levels
        // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
        SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
        SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

        // Asynchronous logging is very fast..
        // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
        async_example();

        // syslog example. linux/osx only
        syslog_example();

        // android example. compile with NDK
        android_example();

        // Log user-defined types example
        user_defined_example();

        // Change default log error handler
        err_handler_example();

        // Apply a function on all registered loggers
159
        spd::apply_all([&](std::shared_ptr<spd::logger> l)
Gabi Melman's avatar
Gabi Melman committed
160 161 162 163 164
        {
            l->info("End of example.");
        });

        // Release and close all loggers
165
        spd::drop_all();
Gabi Melman's avatar
Gabi Melman committed
166 167 168 169 170 171 172
    }
    // Exceptions will only be thrown upon failed logger or sink construction (not during logging)
    catch (const spd::spdlog_ex& ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
        return 1;
    }
gabime's avatar
gabime committed
173 174 175 176 177
}

void async_example()
{
    size_t q_size = 4096; //queue size must be power of 2
178
    spd::set_async_mode(q_size);
gabime's avatar
gabime committed
179 180
    auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
    for (int i = 0; i < 100; ++i)
Gabi Melman's avatar
Gabi Melman committed
181
        async_file->info("Async message #{}", i);
gabime's avatar
gabime committed
182 183
}

Gabi Melman's avatar
Gabi Melman committed
184
//syslog example
gabime's avatar
gabime committed
185 186
void syslog_example()
{
Gabi Melman's avatar
Gabi Melman committed
187
#ifdef SPDLOG_ENABLE_SYSLOG 
gabime's avatar
gabime committed
188 189
    std::string ident = "spdlog-example";
    auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
Gabi Melman's avatar
Gabi Melman committed
190
    syslog_logger->warn("This is warning that will end up in syslog..");
gabime's avatar
gabime committed
191 192 193 194 195 196 197 198 199 200 201
#endif
}

// user defined types logging by implementing operator<<
struct my_type
{
    int i;
    template<typename OStream>
    friend OStream& operator<<(OStream& os, const my_type &c)
    {
        return os << "[my_type i="<<c.i << "]";
gabime's avatar
gabime committed
202
    }
gabime's avatar
gabime committed
203 204 205 206 207 208
};

#include <spdlog/fmt/ostr.h> // must be included
void user_defined_example()
{
    spd::get("console")->info("user defined type: {}", my_type { 14 });
gabime's avatar
gabime committed
209 210
}

gabime's avatar
gabime committed
211 212 213 214 215
//
//custom error handler
//
void err_handler_example()
{	
216
	spd::set_error_handler([](const std::string& msg) {
gabime's avatar
gabime committed
217
		std::cerr << "my err handler: " << msg << std::endl;
Gabi Melman's avatar
Gabi Melman committed
218 219
	}); 
	// (or logger->set_error_handler(..) to set for specific logger)
gabime's avatar
gabime committed
220
}
gabime's avatar
gabime committed
221 222 223 224 225

```

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