README.md 7.61 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)
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
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);
Gabi Melman's avatar
Gabi Melman committed
96
	
Gabi Melman's avatar
Gabi Melman committed
97 98 99 100 101 102
        // 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");
Gabi Melman's avatar
Gabi Melman committed
103 104
	
	// Use global registry to retrieve loggers
Gabi Melman's avatar
Gabi Melman committed
105 106 107 108 109 110 111
        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
112
        auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/mylogfile.txt", 1048576 * 5, 3);
Gabi Melman's avatar
Gabi Melman committed
113 114 115 116
        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
117
        auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
Gabi Melman's avatar
Gabi Melman committed
118 119 120 121 122 123 124 125 126
        // 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
127 128
        // Runtime log levels
	spd::set_level(spd::level::info); //Set global log level to info
Berkus Decker's avatar
Berkus Decker committed
129
	console->debug("This message should not be displayed!");
Gabi Melman's avatar
Gabi Melman committed
130
	console->set_level(spd::level::debug); // Set specific logger's log level
Berkus Decker's avatar
Berkus Decker committed
131
	console->debug("This message should be displayed..");
Gabi Melman's avatar
Gabi Melman committed
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

        // 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
155
        spd::apply_all([&](std::shared_ptr<spd::logger> l)
Gabi Melman's avatar
Gabi Melman committed
156 157 158 159 160
        {
            l->info("End of example.");
        });

        // Release and close all loggers
161
        spd::drop_all();
Gabi Melman's avatar
Gabi Melman committed
162 163 164 165 166 167 168
    }
    // 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
169 170 171 172 173
}

void async_example()
{
    size_t q_size = 4096; //queue size must be power of 2
174
    spd::set_async_mode(q_size);
gabime's avatar
gabime committed
175 176
    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
177
        async_file->info("Async message #{}", i);
gabime's avatar
gabime committed
178 179
}

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

#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
205 206
}

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

```

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