diff --git a/example/example.cpp b/example/example.cpp index 267e4215..c1c3bd3d 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -27,6 +27,7 @@ void custom_flags_example(); void file_events_example(); void replace_default_logger_example(); void mdc_example(); +void syslog_formatter_example(); #include "spdlog/spdlog.h" #include "spdlog/cfg/env.h" // support for loading levels from the environment variable @@ -86,6 +87,7 @@ int main(int, char *[]) { file_events_example(); replace_default_logger_example(); mdc_example(); + syslog_formatter_example(); // Flush all *registered* loggers using a worker thread every 3 seconds. // note: registered loggers *must* be thread safe for this to work correctly! @@ -391,3 +393,14 @@ void mdc_example() spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [%&] %v"); spdlog::info("Some log message with context"); } + +#include "spdlog/syslog_formatter.h" +void syslog_formatter_example() +{ + // run "nc -klu 514" to receive the syslog message + spdlog::sinks::udp_sink_config udp_sink_config("127.0.0.1", 514); + auto udp_logger = spdlog::udp_logger_mt("udp_logger", udp_sink_config); + spdlog::syslog_formatter syslog_formatter(spdlog::facility::user, "localhost", "example"); + udp_logger->set_formatter(syslog_formatter.clone()); + udp_logger->info("this message will be logged in local syslog receiver"); +} diff --git a/include/spdlog/syslog_formatter-inl.h b/include/spdlog/syslog_formatter-inl.h new file mode 100644 index 00000000..ec1cca4e --- /dev/null +++ b/include/spdlog/syslog_formatter-inl.h @@ -0,0 +1,107 @@ +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include + +namespace spdlog { +namespace details { + +namespace severity { + enum severity_enum : int { + emergency = 0, + alert = 1, + critical = 2, + error = 3, + warning = 4, + notice = 5, + informational = 6, + debug = 7, + }; +} + +} // namespace details + +SPDLOG_INLINE syslog_formatter::syslog_formatter(int facility, std::string hostname, std::string appname) + : facility_(facility), + hostname_(std::move(hostname)), + appname_(std::move(appname)), + pattern_formatter_("%Y-%m-%dT%H:%M:%SZ", pattern_time_type::utc, "") { + pattern_formatter_.need_localtime(); +} + +SPDLOG_INLINE std::unique_ptr syslog_formatter::clone() const { + auto cloned = details::make_unique(facility_, hostname_, appname_); +#if defined(__GNUC__) && __GNUC__ < 5 + return std::move(cloned); +#else + return cloned; +#endif +} + +SPDLOG_INLINE void syslog_formatter::format(const details::log_msg &msg, memory_buf_t &dest) { + details::severity::severity_enum severity; + + switch (msg.level) { + case level::critical: + severity = details::severity::critical; + + case level::err: + severity = details::severity::error; + break; + + case level::warn: + severity = details::severity::warning; + break; + + case level::info: + severity = details::severity::informational; + break; + + default: + severity = details::severity::debug; + break; + } + + dest.push_back('<'); + details::fmt_helper::append_int((facility_ * 8) + severity, dest); + dest.push_back('>'); + dest.push_back('1'); + + dest.push_back(' '); + pattern_formatter_.format(msg, dest); + + dest.push_back(' '); + if (hostname_.empty()) { + dest.push_back('-'); + } else { + details::fmt_helper::append_string_view(hostname_, dest); + } + + dest.push_back(' '); + if (appname_.empty()) { + dest.push_back('-'); + } else { + details::fmt_helper::append_string_view(appname_, dest); + } + + dest.push_back(' '); + details::fmt_helper::append_int(details::os::pid(), dest); + + dest.push_back(' '); + if (msg.logger_name.size() == 0) { + dest.push_back('-'); + } else { + details::fmt_helper::append_string_view(msg.logger_name, dest); + } + + dest.push_back(' '); + dest.push_back('-'); // nil structured data + + dest.push_back(' '); + details::fmt_helper::append_string_view(msg.payload, dest); +} + +} // namespace spdlog diff --git a/include/spdlog/syslog_formatter.h b/include/spdlog/syslog_formatter.h new file mode 100644 index 00000000..9392b0df --- /dev/null +++ b/include/spdlog/syslog_formatter.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace spdlog { + +namespace facility { + enum facility_enum : int { + kernel = 0, + user = 1, + mail = 2, + daemons = 3, + security = 4, + syslogd = 5, + printer = 6, + network = 7, + uucp = 8, + clock = 9, + security2 = 10, + ftp = 11, + ntp = 12, + audit = 13, + alert = 14, + clock2 = 15, + local0 = 16, + local1 = 17, + local2 = 18, + local3 = 19, + local4 = 20, + local5 = 21, + local6 = 22, + local7 = 23 + }; +} + +class SPDLOG_API syslog_formatter : public formatter { +public: + explicit syslog_formatter(int facility, std::string hostname, std::string appname); + + syslog_formatter(const syslog_formatter &other) = delete; + syslog_formatter &operator=(const syslog_formatter &other) = delete; + + std::unique_ptr clone() const override; + void format(const details::log_msg &msg, memory_buf_t &dest) override; + +private: + int facility_; + std::string hostname_; + std::string appname_; + spdlog::pattern_formatter pattern_formatter_; +}; + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "syslog_formatter-inl.h" +#endif diff --git a/src/spdlog.cpp b/src/spdlog.cpp index 9f8390bc..467dc11e 100644 --- a/src/spdlog.cpp +++ b/src/spdlog.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include