#include "logger.hh" #include #include #include #include #include #include #include namespace logger { namespace { class BaseLogger : public Logger { protected: enum class Level : uint8_t { kError, kWarning, kInfo, kDebug, }; public: void err(std::string_view message) final { write(Level::kError, message); } void warn(std::string_view message) final { write(Level::kWarning, message); } void info(std::string_view message) final { write(Level::kInfo, message); } #if !defined(NDEBUG) void dbg(std::string_view message) final { write(Level::kDebug, message); } #endif protected: BaseLogger() = default; virtual void write(Level level, std::string_view message) = 0; }; class NoopLogger : public BaseLogger { public: NoopLogger() = default; protected: void write(Level /* level */, std::string_view /* message */) override {} }; class SyslogLogger : public BaseLogger { public: SyslogLogger(std::string ident, bool verbose) : ident_(std::move(ident)), verbose_(verbose) { // NOLINTNEXTLINE(misc-include-cleaner) openlog(ident_.c_str(), LOG_PID | LOG_CONS, LOG_DAEMON); } ~SyslogLogger() override { // NOLINTNEXTLINE(misc-include-cleaner) closelog(); } protected: void write(Level level, std::string_view message) override { // NOLINTNEXTLINE(misc-include-cleaner) int prio = LOG_ERR; switch (level) { case Level::kError: // NOLINTNEXTLINE(misc-include-cleaner) prio = LOG_ERR; break; case Level::kWarning: // NOLINTNEXTLINE(misc-include-cleaner) prio = LOG_WARNING; break; case Level::kInfo: if (!verbose_) return; // NOLINTNEXTLINE(misc-include-cleaner) prio = LOG_INFO; break; case Level::kDebug: if (!verbose_) return; // NOLINTNEXTLINE(misc-include-cleaner) prio = LOG_DEBUG; break; } // NOLINTNEXTLINE(misc-include-cleaner) ::syslog(prio, "%*s", static_cast(message.size()), message.data()); } private: std::string const ident_; bool const verbose_; }; class StderrLogger : public BaseLogger { public: explicit StderrLogger(bool verbose) : verbose_(verbose) {} protected: void write(Level level, std::string_view message) override { switch (level) { case Level::kError: std::cerr << "Error: "; break; case Level::kWarning: std::cerr << "Warning: "; break; case Level::kInfo: if (!verbose_) return; std::cerr << "Info: "; break; case Level::kDebug: if (!verbose_) return; std::cerr << "Debug: "; break; } std::cerr << message << '\n'; } private: bool const verbose_; }; } // namespace [[nodiscard]] std::unique_ptr noop() { return std::make_unique(); } [[nodiscard]] std::unique_ptr syslog(std::string ident, bool verbose) { return std::make_unique(std::move(ident), verbose); } [[nodiscard]] std::unique_ptr stderr(bool verbose) { return std::make_unique(verbose); } } // namespace logger