You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
3.1KB

  1. // Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com
  2. // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3. #pragma once
  4. #include "spdlog/sinks/base_sink.h"
  5. #include "spdlog/details/null_mutex.h"
  6. #include "spdlog/details/synchronous_factory.h"
  7. #include <systemd/sd-journal.h>
  8. namespace spdlog {
  9. namespace sinks {
  10. /**
  11. * Sink that write to systemd journal using the `sd_journal_send()` library call.
  12. *
  13. * Locking is not needed, as `sd_journal_send()` itself is thread-safe.
  14. */
  15. template<typename Mutex>
  16. class systemd_sink : public base_sink<Mutex>
  17. {
  18. public:
  19. //
  20. systemd_sink()
  21. : syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG,
  22. /* spdlog::level::debug */ LOG_DEBUG,
  23. /* spdlog::level::info */ LOG_INFO,
  24. /* spdlog::level::warn */ LOG_WARNING,
  25. /* spdlog::level::err */ LOG_ERR,
  26. /* spdlog::level::critical */ LOG_CRIT,
  27. /* spdlog::level::off */ LOG_INFO}}
  28. {}
  29. ~systemd_sink() override {}
  30. systemd_sink(const systemd_sink &) = delete;
  31. systemd_sink &operator=(const systemd_sink &) = delete;
  32. protected:
  33. using levels_array = std::array<int, 7>;
  34. levels_array syslog_levels_;
  35. void sink_it_(const details::log_msg &msg) override
  36. {
  37. int err;
  38. size_t length = msg.payload.size();
  39. // limit to max int
  40. if (length > static_cast<size_t>(std::numeric_limits<int>::max()))
  41. {
  42. length = static_cast<size_t>(std::numeric_limits<int>::max());
  43. }
  44. // Do not send source location if not available
  45. if (msg.source.empty())
  46. {
  47. // Note: function call inside '()' to avoid macro expansion
  48. err = (sd_journal_send)(
  49. "MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), nullptr);
  50. }
  51. else
  52. {
  53. err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level),
  54. "SOURCE_FILE=%s", msg.source.filename, "SOURCE_LINE=%d", msg.source.line, "SOURCE_FUNC=%s", msg.source.funcname, nullptr);
  55. }
  56. if (err)
  57. {
  58. SPDLOG_THROW(spdlog_ex("Failed writing to systemd", errno));
  59. }
  60. }
  61. int syslog_level(level::level_enum l)
  62. {
  63. return syslog_levels_.at(static_cast<levels_array::size_type>(l));
  64. }
  65. void flush_() override {}
  66. };
  67. using systemd_sink_mt = systemd_sink<std::mutex>;
  68. using systemd_sink_st = systemd_sink<details::null_mutex>;
  69. } // namespace sinks
  70. // Create and register a syslog logger
  71. template<typename Factory = spdlog::synchronous_factory>
  72. inline std::shared_ptr<logger> systemd_logger_mt(const std::string &logger_name)
  73. {
  74. return Factory::template create<sinks::systemd_sink_mt>(logger_name);
  75. }
  76. template<typename Factory = spdlog::synchronous_factory>
  77. inline std::shared_ptr<logger> systemd_logger_st(const std::string &logger_name)
  78. {
  79. return Factory::template create<sinks::systemd_sink_st>(logger_name);
  80. }
  81. } // namespace spdlog