From 3cd01b932e1c85394272ae64fae67ebeda92fb00 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 23:11:59 +0200 Subject: Adding upstream version 1.8.3. Signed-off-by: Daniel Baumann --- logging.hh | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 logging.hh (limited to 'logging.hh') diff --git a/logging.hh b/logging.hh new file mode 100644 index 0000000..0ddf6be --- /dev/null +++ b/logging.hh @@ -0,0 +1,220 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include "config.h" + +#ifdef RECURSOR + +#include +#include +#include +#include +#include + +#include "logr.hh" +#include "dnsname.hh" +#include "iputils.hh" + +namespace Logging +{ + +struct Entry +{ + boost::optional name; // name parts joined with '.' + std::string message; // message as send to log call + boost::optional error; // error if .Error() was called + struct timeval d_timestamp; // time of entry generation + std::map values; // key-value pairs + size_t level; // level at which this was logged + Logr::Priority d_priority; // (syslog) priority) +}; + +// Warning: some meta-programming is going on. We define helper +// templates that can be used to see if specific string output +// functions are available. If so, we use those instead of << into an +// ostringstream. Note that this decision happpens compile time. +// Some hints taken from https://www.cppstories.com/2019/07/detect-overload-from-chars/ +// (I could not get function templates with enabled_if<> to work in this case) +// +// Default: std::string(T) is not available +template +struct is_to_string_available : std::false_type +{ +}; + +// If std::string(T) is available this template is used +template +struct is_to_string_available()))>> : std::true_type +{ +}; + +// Same mechanism for t.toLogString() +template +struct is_toLogString_available : std::false_type +{ +}; + +template +struct is_toLogString_available().toLogString())>> : std::true_type +{ +}; + +template +struct is_toString_available : std::false_type +{ +}; + +template +struct is_toString_available().toString())>> : std::true_type +{ +}; + +template +struct Loggable : public Logr::Loggable +{ + const T& _t; + Loggable(const T& v) : + _t(v) + { + } + std::string to_string() const + { + if constexpr (std::is_same_v) { + return _t; + } + else if constexpr (is_toLogString_available::value) { + return _t.toLogString(); + } + else if constexpr (is_toString_available::value) { + return _t.toString(); + } + else if constexpr (is_to_string_available::value) { + return std::to_string(_t); + } + else { + std::ostringstream oss; + oss << _t; + return oss.str(); + } + } +}; + +template +struct IterLoggable : public Logr::Loggable +{ + const T& _t1; + const T& _t2; + IterLoggable(const T& v1, const T& v2) : + _t1(v1), _t2(v2) + { + } + std::string to_string() const + { + std::ostringstream oss; + bool first = true; + for (auto i = _t1; i != _t2; i++) { + if (!first) { + oss << ' '; + } + else { + first = false; + } + oss << *i; + } + return oss.str(); + } +}; + +typedef void (*EntryLogger)(const Entry&); + +class Logger : public Logr::Logger, public std::enable_shared_from_this +{ +public: + bool enabled(Logr::Priority) const override; + + void info(const std::string& msg) const override; + void info(Logr::Priority, const std::string& msg) const override; + void error(int err, const std::string& msg) const override; + void error(const std::string& err, const std::string& msg) const override; + void error(Logr::Priority, int err, const std::string& msg) const override; + void error(Logr::Priority, const std::string& err, const std::string& msg) const override; + + std::shared_ptr v(size_t level) const override; + std::shared_ptr withValues(const std::map& values) const override; + virtual std::shared_ptr withName(const std::string& name) const override; + + static std::shared_ptr create(EntryLogger callback); + static std::shared_ptr create(EntryLogger callback, const std::string& name); + + Logger(EntryLogger callback); + Logger(EntryLogger callback, boost::optional name); + Logger(std::shared_ptr parent, boost::optional name, size_t verbosity, size_t lvl, EntryLogger callback); + virtual ~Logger(); + + size_t getVerbosity() const; + void setVerbosity(size_t verbosity); + +private: + void logMessage(const std::string& msg, boost::optional err) const; + void logMessage(const std::string& msg, Logr::Priority p, boost::optional err) const; + std::shared_ptr getptr() const; + + std::shared_ptr _parent{nullptr}; + EntryLogger _callback; + boost::optional _name; + std::map _values; + // current Logger's level. the higher the more verbose. + size_t _level{0}; + // verbosity settings. messages with level higher's than verbosity won't appear + size_t _verbosity{0}; +}; +} + +extern std::shared_ptr g_slog; + +// Prefer structured logging? +extern bool g_slogStructured; + +// A helper macro to switch between old-style logging and new-style (structured logging) +// A typical use: +// +// SLOG(g_log<error("No such file", "Unable to parse configuration file", "config_file", Logging::Loggable(configname)); +// +#define SLOG(oldStyle, slogCall) \ + do { \ + if (g_slogStructured) { \ + slogCall; \ + } \ + else { \ + oldStyle; \ + } \ + } while (0); + +#else // No structured logging (e.g. auth) +#define SLOG(oldStyle, slogCall) \ + do { \ + oldStyle; \ + } while (0); +#endif // RECURSOR -- cgit v1.2.3