mirror of
https://github.com/gabime/spdlog.git
synced 2025-04-01 02:42:41 +08:00

This is what my manpage says, and what the original blog post [1] says as well. Also, `sd_journal_send` can add the location of its own invocation to the log. That's typically not what we want, so we have to suppress that feature and instead put whatever is inside the spdlog message into the journal. [1] http://0pointer.de/blog/projects/journal-submit.html
103 lines
3.2 KiB
C++
103 lines
3.2 KiB
C++
// Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com
|
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
|
|
|
#pragma once
|
|
|
|
#include "spdlog/sinks/base_sink.h"
|
|
#include "spdlog/details/null_mutex.h"
|
|
#include "spdlog/details/synchronous_factory.h"
|
|
|
|
#include <array>
|
|
#ifndef SD_JOURNAL_SUPPRESS_LOCATION
|
|
#define SD_JOURNAL_SUPPRESS_LOCATION
|
|
#endif
|
|
#include <systemd/sd-journal.h>
|
|
|
|
namespace spdlog {
|
|
namespace sinks {
|
|
|
|
/**
|
|
* Sink that write to systemd journal using the `sd_journal_send()` library call.
|
|
*
|
|
* Locking is not needed, as `sd_journal_send()` itself is thread-safe.
|
|
*/
|
|
template<typename Mutex>
|
|
class systemd_sink : public base_sink<Mutex>
|
|
{
|
|
public:
|
|
//
|
|
systemd_sink()
|
|
: syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG,
|
|
/* spdlog::level::debug */ LOG_DEBUG,
|
|
/* spdlog::level::info */ LOG_INFO,
|
|
/* spdlog::level::warn */ LOG_WARNING,
|
|
/* spdlog::level::err */ LOG_ERR,
|
|
/* spdlog::level::critical */ LOG_CRIT,
|
|
/* spdlog::level::off */ LOG_INFO}}
|
|
{}
|
|
|
|
~systemd_sink() override {}
|
|
|
|
systemd_sink(const systemd_sink &) = delete;
|
|
systemd_sink &operator=(const systemd_sink &) = delete;
|
|
|
|
protected:
|
|
using levels_array = std::array<int, 7>;
|
|
levels_array syslog_levels_;
|
|
|
|
void sink_it_(const details::log_msg &msg) override
|
|
{
|
|
int err;
|
|
|
|
size_t length = msg.payload.size();
|
|
// limit to max int
|
|
if (length > static_cast<size_t>(std::numeric_limits<int>::max()))
|
|
{
|
|
length = static_cast<size_t>(std::numeric_limits<int>::max());
|
|
}
|
|
|
|
// Do not send source location if not available
|
|
if (msg.source.empty())
|
|
{
|
|
// Note: function call inside '()' to avoid macro expansion
|
|
err = (sd_journal_send)(
|
|
"MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), nullptr);
|
|
}
|
|
else
|
|
{
|
|
err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level),
|
|
"CODE_FILE=%s", msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr);
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
SPDLOG_THROW(spdlog_ex("Failed writing to systemd", errno));
|
|
}
|
|
}
|
|
|
|
int syslog_level(level::level_enum l)
|
|
{
|
|
return syslog_levels_.at(static_cast<levels_array::size_type>(l));
|
|
}
|
|
|
|
void flush_() override {}
|
|
};
|
|
|
|
using systemd_sink_mt = systemd_sink<std::mutex>;
|
|
using systemd_sink_st = systemd_sink<details::null_mutex>;
|
|
} // namespace sinks
|
|
|
|
// Create and register a syslog logger
|
|
template<typename Factory = spdlog::synchronous_factory>
|
|
inline std::shared_ptr<logger> systemd_logger_mt(const std::string &logger_name)
|
|
{
|
|
return Factory::template create<sinks::systemd_sink_mt>(logger_name);
|
|
}
|
|
|
|
template<typename Factory = spdlog::synchronous_factory>
|
|
inline std::shared_ptr<logger> systemd_logger_st(const std::string &logger_name)
|
|
{
|
|
return Factory::template create<sinks::systemd_sink_st>(logger_name);
|
|
}
|
|
} // namespace spdlog
|