Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a trivial callback sink #2610

Merged
merged 4 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,28 @@ void multi_sink_example()
}
```

---
#### Logger with a custom callback function that receives the logs
```c++

// create 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.debug("some debug log");
logger.error("critical issue"); // will notify you
}
```

---
#### Asynchronous logging
```c++
Expand Down
11 changes: 11 additions & 0 deletions example/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ void stdout_logger_example();
void basic_example();
void rotating_example();
void daily_example();
void callback_example();
void async_example();
void binary_example();
void vector_example();
Expand Down Expand Up @@ -72,6 +73,7 @@ int main(int, char *[])
basic_example();
rotating_example();
daily_example();
callback_example();
async_example();
binary_example();
vector_example();
Expand Down Expand Up @@ -136,6 +138,15 @@ void daily_example()
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

#include "spdlog/sinks/callback_sink.h"
void callback_example()
{
// Create the logger
auto logger = spdlog::callback_logger_mt("custom_callback_logger", [](const spdlog::details::log_msg &/*msg*/) {
// do what you need to do with msg
});
}

#include "spdlog/cfg/env.h"
void load_levels_example()
{
Expand Down
61 changes: 61 additions & 0 deletions include/spdlog/sinks/callback_sink.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/synchronous_factory.h>

#include <mutex>
#include <string>

namespace spdlog {

// callbacks type
typedef std::function<void(const details::log_msg &msg)> custom_log_callback;

namespace sinks {
/*
* Trivial callback sink, gets a callback function and calls it on each log
*/
template<typename Mutex>
class callback_sink final : public base_sink<Mutex>
{
public:
explicit callback_sink(const custom_log_callback &callback)
: callback_{callback}
{}

protected:
void sink_it_(const details::log_msg &msg) override
{
callback_(msg);
}
void flush_() override{};

private:
custom_log_callback callback_;
};

using callback_sink_mt = callback_sink<std::mutex>;
using callback_sink_st = callback_sink<details::null_mutex>;

} // namespace sinks

//
// factory functions
//
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> callback_logger_mt(const std::string &logger_name, const custom_log_callback &callback)
{
return Factory::template create<sinks::callback_sink_mt>(logger_name, callback);
}

template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> callback_logger_st(const std::string &logger_name, const custom_log_callback &callback)
{
return Factory::template create<sinks::callback_sink_st>(logger_name, callback);
}

} // namespace spdlog
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ set(SPDLOG_UTESTS_SOURCES
test_stdout_api.cpp
test_backtrace.cpp
test_create_dir.cpp
test_custom_callbacks.cpp
test_cfg.cpp
test_time_point.cpp
test_stopwatch.cpp)
Expand Down
34 changes: 34 additions & 0 deletions tests/test_custom_callbacks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/
#include "includes.h"
#include "test_sink.h"
#include "spdlog/sinks/callback_sink.h"
#include "spdlog/async.h"
#include "spdlog/common.h"

TEST_CASE("custom_callback_logger", "[custom_callback_logger]]")
{
std::vector<std::string> lines;
spdlog::pattern_formatter formatter;
auto callback_logger = std::make_shared<spdlog::sinks::callback_sink_st>([&](const spdlog::details::log_msg &msg) {
spdlog::memory_buf_t formatted;
formatter.format(msg, formatted);
auto eol_len = strlen(spdlog::details::os::default_eol);
lines.emplace_back(formatted.begin(), formatted.end() - eol_len);
});
std::shared_ptr<spdlog::sinks::test_sink_st> test_sink(new spdlog::sinks::test_sink_st);

spdlog::logger logger("test-callback", {callback_logger, test_sink});

logger.info("test message 1");
logger.info("test message 2");
logger.info("test message 3");

std::vector<std::string> ref_lines = test_sink->lines();

REQUIRE(lines[0] == ref_lines[0]);
REQUIRE(lines[1] == ref_lines[1]);
REQUIRE(lines[2] == ref_lines[2]);
spdlog::drop_all();
}