Git Product home page Git Product logo

spdlog's Introduction

spdlog

Very fast, header-only/compiled, C++ logging library. ci  Build status Release

Install

Header-only version

Copy the include folder to your build tree and use a C++11 compiler.

Compiled version (recommended - much faster compile times)

$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && make -j

see example CMakeLists.txt on how to use.

Platforms

  • Linux, FreeBSD, OpenBSD, Solaris, AIX
  • Windows (msvc 2013+, cygwin)
  • macOS (clang 3.5+)
  • Android

Package managers:

  • Debian: sudo apt install libspdlog-dev
  • Homebrew: brew install spdlog
  • MacPorts: sudo port install spdlog
  • FreeBSD: pkg install spdlog
  • Fedora: dnf install spdlog
  • Gentoo: emerge dev-libs/spdlog
  • Arch Linux: pacman -S spdlog
  • openSUSE: sudo zypper in spdlog-devel
  • vcpkg: vcpkg install spdlog
  • conan: spdlog/[>=1.4.1]
  • conda: conda install -c conda-forge spdlog
  • build2: depends: spdlog ^1.8.2

Features

  • Very fast (see benchmarks below).
  • Headers only or compiled
  • Feature-rich formatting, using the excellent fmt library.
  • Asynchronous mode (optional)
  • Custom formatting.
  • Multi/Single threaded loggers.
  • Various log targets:
    • Rotating log files.
    • Daily log files.
    • Console logging (colors supported).
    • syslog.
    • Windows event log.
    • Windows debugger (OutputDebugString(..)).
    • Log to Qt widgets (example).
    • Easily extendable with custom log targets.
  • Log filtering - log levels can be modified at runtime as well as compile time.
  • Support for loading log levels from argv or environment var.
  • Backtrace support - store debug messages in a ring buffer and display them later on demand.

Usage samples

Basic usage

#include "spdlog/spdlog.h"

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");
    
    spdlog::set_level(spdlog::level::debug); // Set global log level to debug
    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
    // Note that this does not change the current log level, it will only
    // remove (depending on SPDLOG_ACTIVE_LEVEL) the call on the release code.
    SPDLOG_TRACE("Some trace message with param {}", 42);
    SPDLOG_DEBUG("Some debug message");
}

Create stdout/stderr logger object

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
{
    // create a color multi-threaded logger
    auto console = spdlog::stdout_color_mt("console");    
    auto err_logger = spdlog::stderr_color_mt("stderr");    
    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}

Basic file logger

#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{
    try 
    {
        auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
    }
}

Rotating files

#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5 MB size max and 3 rotated files
    auto max_size = 1048576 * 5;
    auto max_files = 3;
    auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files);
}

Daily files

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

Backtrace support

// Debug messages can be stored in a ring buffer instead of being logged immediately.
// This is useful to display debug logs only when needed (e.g. when an error happens).
// When needed, call dump_backtrace() to dump them to your log.

spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. 
// or my_logger->enable_backtrace(32)..
for(int i = 0; i < 100; i++)
{
  spdlog::debug("Backtrace message {}", i); // not logged yet..
}
// e.g. if some error happened:
spdlog::dump_backtrace(); // log them now! show the last 32 messages
// or my_logger->dump_backtrace(32)..

Periodic flush

// periodically flush all *registered* loggers every 3 seconds:
// warning: only use if all your loggers are thread-safe ("_mt" loggers)
spdlog::flush_every(std::chrono::seconds(3));

Stopwatch

// Stopwatch support for spdlog
#include "spdlog/stopwatch.h"
void stopwatch_example()
{
    spdlog::stopwatch sw;    
    spdlog::debug("Elapsed {}", sw);
    spdlog::debug("Elapsed {:.3}", sw);       
}

Log binary data in hex

// 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 into lines.
// {:a} - show ASCII if :n is not set.

#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));
}

Logger with multi sinks - each with a different format and log level

// create a logger with 2 targets, with different log levels and formats.
// The console will show only warnings or errors, while the file will log all.
void multi_sink_example()
{
    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");

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);

    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");
}

User-defined callbacks about log events

// create a logger with a lambda function callback, the callback will be called
// each time something is logged to the logger
void callback_example()
{
    auto callback_sink = std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg &msg) {
         // for example you can be notified by sending an email to yourself
    });
    callback_sink->set_level(spdlog::level::err);

    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    spdlog::logger logger("custom_callback_logger", {console_sink, callback_sink});

    logger.info("some info log");
    logger.error("critical issue"); // will notify you
}

Asynchronous logging

#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

#include "spdlog/async.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"

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);
}

User-defined types

template<>
struct fmt::formatter<my_type> : fmt::formatter<std::string>
{
    auto format(my_type my, format_context &ctx) const -> decltype(ctx.out())
    {
        return format_to(ctx.out(), "[my_type i={}]", my.i);
    }
};

void user_defined_example()
{
    spdlog::info("user defined type: {}", my_type(14));
}

User-defined flags in the log pattern

// Log patterns can contain custom flags.
// the following example will add new flag '%*' - which will be bound to a <my_formatter_flag> instance.
#include "spdlog/pattern_formatter.h"
class my_formatter_flag : public spdlog::custom_flag_formatter
{
public:
    void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
    {
        std::string some_txt = "custom-flag";
        dest.append(some_txt.data(), some_txt.data() + some_txt.size());
    }

    std::unique_ptr<custom_flag_formatter> clone() const override
    {
        return spdlog::details::make_unique<my_formatter_flag>();
    }
};

void custom_flags_example()
{    
    auto formatter = std::make_unique<spdlog::pattern_formatter>();
    formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    spdlog::set_formatter(std::move(formatter));
}

Custom error handler

void err_handler_example()
{
    // 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);
}

syslog

#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{
    std::string ident = "spdlog-example";
    auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
}

Android example

#include "spdlog/sinks/android_sink.h"
void android_example()
{
    std::string tag = "spdlog-android";
    auto android_logger = spdlog::android_logger_mt("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
}

Load log levels from the env variable or argv

#include "spdlog/cfg/env.h"
int main (int argc, char *argv[])
{
    spdlog::cfg::load_env_levels();
    // or from the command line:
    // ./example SPDLOG_LEVEL=info,mylogger=trace
    // #include "spdlog/cfg/argv.h" // for loading levels from argv
    // spdlog::cfg::load_argv_levels(argc, argv);
}

So then you can:

$ export SPDLOG_LEVEL=info,mylogger=trace
$ ./example

Log file open/close event handlers

// You can get callbacks from spdlog before/after a log file has been opened or closed. 
// This is useful for cleanup procedures or for adding something to the start/end of the log file.
void file_events_example()
{
    // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications
    spdlog::file_event_handlers handlers;
    handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); };
    handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("After opening\n", fstream); };
    handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("Before closing\n", fstream); };
    handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); };
    auto my_logger = spdlog::basic_logger_st("some_logger", "logs/events-sample.txt", true, handlers);        
}

Replace the Default Logger

void replace_default_logger_example()
{
    auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true);
    spdlog::set_default_logger(new_logger);
    spdlog::info("new logger log message");
}

Log to Qt with nice colors

#include "spdlog/spdlog.h"
#include "spdlog/sinks/qt_sinks.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    setMinimumSize(640, 480);
    auto log_widget = new QTextEdit(this);
    setCentralWidget(log_widget);
    int max_lines = 500; // keep the text widget to max 500 lines. remove old lines if needed.
    auto logger = spdlog::qt_color_logger_mt("qt_logger", log_widget, max_lines);
    logger->info("Some info message");
}

Benchmarks

Below are some benchmarks 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, competing over the same logger object, 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

[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] -------------------------------------------------
[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

Documentation

Documentation can be found in the wiki pages.


Thanks to JetBrains for donating product licenses to help develop spdlog

spdlog's People

Contributors

a-martynovich avatar alzix avatar asit-dhal avatar cjlove avatar d-r-p-3-p-p-3-r avatar danielchabrowski avatar davidzemon avatar dominicpoeschko avatar eudoxos avatar fawdlstty avatar fegomes avatar fooinha avatar gabi120 avatar gabime avatar gnzlbg avatar godbyk avatar jcelerier avatar jktjkt avatar kasru avatar matt77hias avatar mensinda avatar mguludag avatar odeits avatar offa avatar pedrorod avatar proheeler avatar pwm1234-sri avatar stevenlunt avatar sylveon avatar xvitaly avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spdlog's Issues

Question: stdout/stderr loggers synchronization

By walking the code-base I've checked that differently named console loggers like spd::stdout_logger_mt("A"), spd::stdout_logger_mt("B"), ... seem to create a stdout_sink_mt for each. Each will be protected by independent std::mutexs right? So,

  • Is it expected for these default multi-threaded stdout loggers not to be synchronized?
  • If so, isn't this worth to be explicitly documented?

I ask this because if this is the behaviour that has been implemented, it's quite likely that a user will not expect that by having multiple named multi-threaded stdout loggers they won't be in sync solely because of their name.

Mingw build

Using 4.9.1 mingw64 and building examples

  1. make all in examples dir doesn't find 'makefile'. Recapitalise to 'Makefile' and all OK

  2. details/os.h uses GetDynamicTimeZoneInfo from windows.h
    mingw defaults to _WIN32_WINNT=0x502 (XP) so doesn't find this newer api

a) Adjust Makefile to add -D_WIN32_WINNT=0x600 or
b) add logic into os.h to cater for this or adapt to XP targets by using a different API

  1. Same function in os.h reports unused variable warning for tm

inline int utc_minutes_offset(const std::tm& tm = localtime())
{

ifdef _WIN32

(void)tm;   // avoid unused param warning

'yield' was not declared in this scope

when cross compiling the project with a gcc 4.8.2. i do get the error message:

./src/async_log_helper.h:273:22: error: 'yield' was not declared in this scope

Ability to prepend/suffix a file when created?

I am looking to create a log file in an xml or json format, but this requires some file header and footer information.

To do this, I need to add the header only once when the file is created and then put in the footer as the file is closed (but also remove it if it was there previously, so that it appends new entries properly). Is this something that can be added?

Document how to create your own logger

Easily extendable with custom log targets (just implement a single function in the sink interface).

E.g. an example for a single file logger (no-rotatory file logger) should be easy to add.

Compilation error

because of

_priorities[static_cast(level::ALWAYS)] = LOG_INFO;

in spdlog/sinks/syslog_sinks.h

from commit log I think this line can be safely removed ?

Consider revisiting streaming pointers

In format.h, there are a pair of constructors that are made private to avoid the streaming of [const] volatile char *:

    // The following two methods are private to disallow formatting of
    // arbitrary pointers. If you want to output a pointer cast it to
    // "void *" or "const void *". In particular, this forbids formatting
    // of "[const] volatile char *" which is printed as bool by iostreams.
    // Do not implement!
    template <typename T>
    MakeValue(const T *value);
    template <typename T>
    MakeValue(T *value);

In all cases besides these, the user just wants to see the hex value for the pointer anyway so I think the restriction created by these private constructors is too onerous and the goal could be achieved by making private constructors that overload on [const] volatile char * unless I'm missing something totally obvious.

How to share a logger between processes?

My application needs to fork an unknown number of processes but I want them all to log to the same file at runtime. Is it possible and advisable to share an instance of shared_ptr between all processes?

Benchmark against Log4* ?

An improvement suggestion: I'd be curious to know how several members of Log4* C/C++ family (log4c, log4cxx and especially log4qt) fare on the same benchmark as the other logging libraries that you've already benchmarked :)
TIA.

SPDLOG_TRACE macro does not work as expected

I've tried to enable the trace and debug logging using macros as shown in the example.

It seems like the level (enum) definitions have changed since the creation of these lines in the example demonstrating the macro use.

So I changed level::DEBUG to spdlog::level::debug and did the same for the trace. I think it is a good idea to fully state the namespace (spdlog) because otherwise a using namespace spdlog is necessary in order to be able to use the macros.

This way, the debug macro works fine. But the trace macro only logs the filename of the current source file.

call: SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
msg: *** [22:08:13 +01:00] [thread 10767463625927578443] example.cpp ***

This behavior results from the signature of force_log which does not expect any file or line number information but gets called this way:

call: logger->force_log(spdlog::level::TRACE, __FILE__, " #", __LINE__,": " __VA_ARGS__)
definition: force_log(level::level_enum lvl, const char* fmt, const Args&... args)

So I assume that the force_log function once accepted this kind of arguments. I couldn't find this state in the Git history. How can this be fixed? How was it intended to work?

spdlog creates a new log file per call to logger

I've setup spdlog the following way:

shared_ptr<logger> init_logger(const Settings& settings) {
    spdlog::set_level(spdlog::level::debug);
    try {
      return rotating_logger_mt(kAppName,
                                settings.logfile,
                                settings.max_file_size,
                                settings.max_files,
                                false);
    }catch (const spdlog_ex& e) {
      throw logic_error(e.what());
    }
}

with settings.logfile, settings.max_file_size and settings.max_files being

logfile = emperor.log
max_file_size = 10
max_files = 10

I'm only using it in a main.cpp file and call it the following way:

uv_loop_t* loop = uv_default_loop();
  try {
    // Init logging.
    logging = init_logger(settings);
    logging->info() << "Init logger";

    stringstream error;
    uv_pipe_t server;
    uint16_t retrn = uv_pipe_init(loop, &server, 0);
    logging->info() << "Init pipe";
    if (retrn < 0) {
      error << "Error initializing pipe: " << uv_strerror(retrn);
      logging->error(error.str().c_str());
      throw logic_error(error.str());
    }

    retrn = uv_pipe_bind(&server, settings.socket_file.c_str());
    logging->info() << "Bind to pipe";
    if (retrn < 0) {
      error << "Error binding to socket " << settings.socket_file << ": " << uv_strerror(retrn);
      logging->error(error.str().c_str());
      throw logic_error(error.str());
    }

    retrn = uv_listen((uv_stream_t*) &server, 128, on_new_connection);
    logging->info() << "Listen on pipe";
    if (retrn < 0) {
      error << "Listen error: " << uv_strerror(retrn);
      logging->error(error.str().c_str());
      throw logic_error(error.str());
    }

  }catch(const logic_error& e) {
    logging->error() << e.what();
    return 2;
  }

The problem is that each call to logging->info() seems to generate a new log file so after my program has run I end up with several log files: emperor.txt, emperor.1.txt, emperor.2.txt.

source file + line no

would be very cool to have an option to output source file + line no in debug logging. is it easily doable? thx

Request: extern C API

It would be nice to use spdlog from Rust (and perhaps other languages with a C FFI).

:-)

spdlog::stdout_logger_st requires pthreads

Hi,

I'm not sure if it's a bug, or a feature, so here's the issue anyways. I've read the documentation and decided to start using spdlog in my (for now, single-threaded) project. Thus, I figured that spdlog::stdout_logger_mt won't bring me anything and spdlog::stdout_logger_st is the right choice. However, as I compiled the project, I've got a bunch of linking errors connected to pthreads. Adding -pthread or -fopenmp switch to the driver invocation fixed them.

So, the question is whether the single-threaded logger is supposed to be usable without threads at all? This is what I would have expected, and I think that it would be a fairly useful property. If not, then I beg my pardon, but it would be nice at least to have it documented.

As a corollary, is my understanding correct that if I ever go for -fopenmp, I wouldn't need threading support explicitly, as -pthread will be magically brought in by -fopenmp, or this is platform/compiler dependent?

Many thanks!

valgrind : 4,096 bytes in 1 blocks are definitely lost in loss record

=77204== 4,096 bytes in 1 blocks are definitely lost in loss record 823 of 856
==77204== at 0x10014B5CB: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==77204== by 0x1017BE856: __smakebuf (in /usr/lib/system/libsystem_c.dylib)
==77204== by 0x1017D33A7: __swsetup (in /usr/lib/system/libsystem_c.dylib)
==77204== by 0x1017BDAF0: __sfvwrite (in /usr/lib/system/libsystem_c.dylib)
==77204== by 0x1017BE0CA: fwrite (in /usr/lib/system/libsystem_c.dylib)
==77204== by 0x1000665E5: spdlog::details::file_helper::write(spdlog::details::log_msg const&) [clone .lto_priv.91](in ./dist/Debug/GNU-MacOSX/lightq)
==77204== by 0x100002B06: spdlog::sinks::rotating_file_sinkstd::mutex::_sink_it(spdlog::details::log_msg const&) [clone .lto_priv.258](in ./dist/Debug/GNU-MacOSX/lightq)
==77204== by 0x100001E9B: spdlog::sinks::base_sinkstd::mutex::log(spdlog::details::log_msg const&) [clone .lto_priv.257](in ./dist/Debug/GNU-MacOSX/lightq)
==77204== by 0x10006B0D1: spdlog::logger::_log_msg(spdlog::details::log_msg&) [clone .lto_priv.2365](in ./dist/Debug/GNU-MacOSX/lightq)
==77204== by 0x10006ABCF: spdlog::details::line_logger::~line_logger() [clone .lto_priv.2016](in ./dist/Debug/GNU-MacOSX/lightq)

osx clion compile error.. support?

Hi. I'm new spdlog user & English :)

I met this error message.
I want use this great logging library!! (love async mod logging!!)

my OSX g++ version

g++ --version                                                                       ✚ ✱ ◼
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
"/Applications/CLion EAP.app/Contents/bin/cmake/bin/cmake" --build /Users/md/Library/Caches/clion10/cmake/generated/34156cd6/34156cd6/Debug --target timo_echoes -- -j 4
Scanning dependencies of target timo_echoes
[100%] Building CXX object CMakeFiles/timo_echoes.dir/main.cpp.o
In file included from /Users/md/Documents/workspace/timo-echoes/main.cpp:22:
In file included from /Users/md/Documents/workspace/timo-echoes/spdlog/include/spdlog/spdlog.h:34:
In file included from /Users/md/Documents/workspace/timo-echoes/spdlog/include/spdlog/logger.h:36:
In file included from /Users/md/Documents/workspace/timo-echoes/spdlog/include/spdlog/sinks/base_sink.h:35:
In file included from /Users/md/Documents/workspace/timo-echoes/spdlog/include/spdlog/sinks/./sink.h:27:
In file included from /Users/md/Documents/workspace/timo-echoes/spdlog/include/spdlog/sinks/../details/log_msg.h:28:
In file included from /Users/md/Documents/workspace/timo-echoes/spdlog/include/spdlog/sinks/../details/./format.h:2880:
/Users/md/Documents/workspace/timo-echoes/spdlog/include/spdlog/sinks/../details/format.cc:145:11: error: cannot initialize a variable of type 'char *' with an rvalue of type 'int'
    char *message = strerror_r(error_code, buffer, buffer_size);
          ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
make[3]: *** [CMakeFiles/timo_echoes.dir/main.cpp.o] Error 1
make[2]: *** [CMakeFiles/timo_echoes.dir/all] Error 2
make[1]: *** [CMakeFiles/timo_echoes.dir/rule] Error 2
make: *** [timo_echoes] Error 2

Syslog dependency fails on windows builds

Compiling examples on mingw
cd example
make --makefile=Makefile.mingw all

Fails due to an missing syslog sink on windows

Quick fix: Wrap function include/spdlog/details/spdlog_impl.h:88

#ifdef __linux__
// Create syslog logger
inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name)
{
    return create<spdlog::sinks::syslog_sink>(logger_name);
}
#endif

Or create dummy windows impl in syslog_sink.h - skip syslog.h include and make log function empty on windows?

thread-safe console output?

is spdlog meant to be thread-safe?
I have 3 loggers in multiple threads and the output in the console looks a little messed up like this:

[11:52:57] [logger1] [info] some log message
[[1111::5522::5577]]  [[lwneoggseoa1k]e 2r[]n o[tiincfeo]]  ENnoO cdeaatna  Lteoa rsneMnodd
e ON

it should more look like

[11:52:58] [logger1] [info] some log message
[11:52:58] [logger2] [info] another log message
[11:52:58] [logger3] [notice] the last log message

travis-ci unit tests

@gabime:
Would you consider writing some unit/regression tests and a .travis.yml file so that they run on each git push? I had to fix a few minor bugs last time I did a git subtree pull. I'd especially like to see the bench program run on each git push on travis-ci so we can easily see if a commit introduces any performance regressions.

Here is an example C++11 project .travis.yml file you could base yours off of, if you've never used travis-ci before, it's super straightforward to get started:
https://github.com/zaphoyd/websocketpp/blob/master/.travis.yml

I do not have time to do this myself right now or I'd submit this as a pull request. If I have time this summer, I'll add some performance/unit tests as well, but maybe you could start with lightly modified versions of the example or bench programs that output the max message rate/sec, time to log 1,000,000 entries with each of the various logging methods (sync st file, async mt file, async st file, etc.)? Then move on to unit tests of the public API?

If you don't have time, thanks again for taking your time to write this library in the first place. :-)

Document the levels provided

namespace level
{
typedef enum
{
    trace    = 0,
    debug    = 1,
    info     = 2,
    notice   = 3,
    warn     = 4,
    err      = 5,
    critical = 6,
    alert    = 7,
    emerg    = 8,
    off      = 9
} level_enum;

Changing pattern dynamically?

I am trying to write a logger that outputs in different formats (JSON, XML, Text, etc). To do so, I need to initially write out a opening tag, then log the entries, then write a closing tag. I attempted to do this by setting the pattern on instantiation and then during destruction, but I seem to be running into issues, and the set_pattern seems to reset the file.

Can the pattern be changed dynamically?

Edit: It was an oops on my side...I accidentally did not initialize the SizeInMB variable and it ended up writing a new log entry for every record.

Compile Errors on Mac OSX Yosemite

When compiling on mac against clang LLVM 3.5, I have the following compilation error,

spdlog/include/spdlog/sinks/../details/./os.h:188:12: error: cannot initialize return object of type 'size_t' (aka 'unsigned long') with an rvalue of type 'pthread_t' (aka '_opaque_pthread_t *')
    return pthread_self();

if you look at the file os.h, under the function:

inline size_t thread_id()
{

#ifdef SPDLOG_NO_THREAD_ID
    return 0;
#else

#ifdef _WIN32
    return ::GetCurrentThreadId();
#elif __linux__
    return  syscall(SYS_gettid);
#else
    return pthread_self();
#endif
#endif //SPDLOG_NO_THREAD_ID
}

spdlog attempts to return the struct pthread_t which resolves to a pointer of type _opaque_pthread_t * of the current thread as the thread id however there is no implicit conversion for this to size_t. A workaround is to cast the pointer to size_t.

Build with warnings

Hello,

On my system (debian Jessie, g++ 4.9.1) the provided examples compiles with warnings.
I am not sure how to fix theses (expect disabling the unused-parameter warnings). This may be annoying for project using spdlog, as it clutter the build log.

Here is my build log: https://gist.github.com/xaqq/8cafb1c2d787e0090f3f

Thanks,

Support for PID?

Currently the library supports thread ids but not PID. I think that even thought it's a repetitive information, it may be useful for later querying stored logs by PID. I'm asking since I see some other libraries support this, and I believe this is one of the reasons.

Locales

I'm sorry this is not a real issue rather a question, but I'm trying to understand how to modify the locale used by spdlog but I haven't been able to find locale or imbue function inside of it.

But given

double theta = -0.142566

cout << theta;
prints -0.142566
while
log.error() << theta;
prints -0,142566

Issue with clock_gettime

Compiling the current head of spdlog in my project throws the following error

out/g++-debug/testbed/TestbedARAClient.o: In function `spdlog::details::os::now()':
/home/mfrey/testbed/ara-sim/spdlog/include/spdlog/sinks/../details/./os.h:51: 
undefined reference to `clock_gettime'
collect2: error: ld returned 1 exit status
Makefile:251: recipe for target 'out/g++-debug/testbed/TestbedDaemon' failed
make: *** [out/g++-debug/testbed/TestbedDaemon] Error 1

Apparently, this can be solved adding -lrt to the linker flags in the makefile. If I compile the code on my development machine (without adding the -lrt flag and using clang++) the code compiles fine nevertheless. I'm not sure if this is an issue with the fairly old Debian on the server (I'm working on)? However, I thought it might be helpful for somebody who runs into the same issue.

Support the ability to filter out sensitive data

I have an application that logs network calls so it is at the very lowest level. Within this trace, a password may appear, usually in some pattern like <password>whatever</password>. I couldn't think of a sanctioned way to turn this into <password>[redacted]</password> so it doesn't mean there isn't one, but if there isn't, I'd like there to be!

Other logging frameworks have this. I wonder if a compiled regex would be sufficient.

Document loggers with multiple sinks

E.g. I would like to have a file logger, but that at compile-time/run-time would also display the output to the screen. I can achieve this by wrapping two loggers. But I could also do this by having a single logger with 2 sinks and setting the level to the console sink to on/off (i.e. having a different level per sink in the logger with multiple sinks).

I think wrapping two different loggers is better, but without documentation about loggers with multiple sinks it is hard to know what is the best way to achieve what I want to do.

ASync sink should use CAS style intrusive pointer when only using one backing thread

Creating a queue which uses a CAS style intrusive linked list for pushed items seems like a good candidate for the async logger. It currently have multiple producers but on a single consumer.

This would allow for pushing items being a simple CAS of a pointer (with loop for conflicts) and a consumer doing the same and just revering the order of the popped data.

The overhead of using a mutex would then go away and probably improve the performance for the async logger.

Question on Logging Output

Hi,

I've got the "issue" that the logging output (file logger) is not written immediately to the logfile. I'm wondering if it is possible to "flush" from time to time the logging output to the file?

I've also got the weird behavior that the console logging ist not writen immediatly to stdout. Is that on purpose or is this most likely an issue in my code?

Thanks in advance!
Best,
Michael

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.