2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <boost/optional.hpp>
44 boost::optional<std::string> name; // name parts joined with '.'
45 std::string message; // message as send to log call
46 boost::optional<std::string> error; // error if .Error() was called
47 struct timeval d_timestamp; // time of entry generation
48 std::map<std::string, std::string> values; // key-value pairs
49 size_t level; // level at which this was logged
50 Logr::Priority d_priority; // (syslog) priority)
53 // Warning: some meta-programming is going on. We define helper
54 // templates that can be used to see if specific string output
55 // functions are available. If so, we use those instead of << into an
56 // ostringstream. Note that this decision happpens compile time.
57 // Some hints taken from https://www.cppstories.com/2019/07/detect-overload-from-chars/
58 // (I could not get function templates with enabled_if<> to work in this case)
60 // Default: std::string(T) is not available
61 template <typename T, typename = void>
62 struct is_to_string_available : std::false_type
66 // If std::string(T) is available this template is used
68 struct is_to_string_available<T, std::void_t<decltype(std::to_string(std::declval<T>()))>> : std::true_type
72 // Same mechanism for t.toLogString() and t.toStructuredLogString()
73 template <typename T, typename = void>
74 struct is_toLogString_available : std::false_type
79 struct is_toLogString_available<T, std::void_t<decltype(std::declval<T>().toLogString())>> : std::true_type
83 template <typename T, typename = void>
84 struct is_toStructuredLogString_available : std::false_type
89 struct is_toStructuredLogString_available<T, std::void_t<decltype(std::declval<T>().toStructuredLogString())>> : std::true_type
93 template <typename T, typename = void>
94 struct is_toString_available : std::false_type
99 struct is_toString_available<T, std::void_t<decltype(std::declval<T>().toString())>> : std::true_type
103 const char* toTimestampStringMilli(const struct timeval& tval, std::array<char, 64>& buf, const std::string& format = "%s");
105 template <typename T>
106 struct Loggable : public Logr::Loggable
109 Loggable(const T& v) :
113 std::string to_string() const
115 if constexpr (std::is_same_v<T, std::string>) {
118 else if constexpr (is_toStructuredLogString_available<T>::value) {
119 return _t.toStructuredLogString();
121 else if constexpr (is_toLogString_available<T>::value) {
122 return _t.toLogString();
124 else if constexpr (is_toString_available<T>::value) {
125 return _t.toString();
127 else if constexpr (is_to_string_available<T>::value) {
128 return std::to_string(_t);
131 std::ostringstream oss;
138 template <typename T>
139 struct IterLoggable : public Logr::Loggable
143 IterLoggable(const T& v1, const T& v2) :
147 std::string to_string() const
149 std::ostringstream oss;
151 for (auto i = _t1; i != _t2; i++) {
164 typedef void (*EntryLogger)(const Entry&);
166 class Logger : public Logr::Logger, public std::enable_shared_from_this<const Logger>
169 bool enabled(Logr::Priority) const override;
171 void info(const std::string& msg) const override;
172 void info(Logr::Priority, const std::string& msg) const override;
173 void error(int err, const std::string& msg) const override;
174 void error(const std::string& err, const std::string& msg) const override;
175 void error(Logr::Priority, int err, const std::string& msg) const override;
176 void error(Logr::Priority, const std::string& err, const std::string& msg) const override;
178 std::shared_ptr<Logr::Logger> v(size_t level) const override;
179 std::shared_ptr<Logr::Logger> withValues(const std::map<std::string, std::string>& values) const override;
180 virtual std::shared_ptr<Logr::Logger> withName(const std::string& name) const override;
182 static std::shared_ptr<Logger> create(EntryLogger callback);
183 static std::shared_ptr<Logger> create(EntryLogger callback, const std::string& name);
185 Logger(EntryLogger callback);
186 Logger(EntryLogger callback, boost::optional<std::string> name);
187 Logger(std::shared_ptr<const Logger> parent, boost::optional<std::string> name, size_t verbosity, size_t lvl, EntryLogger callback);
190 size_t getVerbosity() const;
191 void setVerbosity(size_t verbosity);
194 void logMessage(const std::string& msg, boost::optional<const std::string> err) const;
195 void logMessage(const std::string& msg, Logr::Priority p, boost::optional<const std::string> err) const;
196 std::shared_ptr<const Logger> getptr() const;
198 std::shared_ptr<const Logger> _parent{nullptr};
199 EntryLogger _callback;
200 boost::optional<std::string> _name;
201 std::map<std::string, std::string> _values;
202 // current Logger's level. the higher the more verbose.
204 // verbosity settings. messages with level higher's than verbosity won't appear
205 size_t _verbosity{0};
209 extern std::shared_ptr<Logging::Logger> g_slog;
211 // Prefer structured logging? Since Recursor 5.1.0, we always do. We keep a const, to allow for
212 // step-by-step removal of old style logging code (for recursor-only code). Note that code shared
213 // with auth still uses old-style, so the SLOG calls should remain for shared code.
214 constexpr bool g_slogStructured = true;
216 // A helper macro to switch between old-style logging and new-style (structured logging)
219 // SLOG(g_log<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl,
220 // startupLog->error("No such file", "Unable to parse configuration file", "config_file", Logging::Loggable(configname));
222 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
223 #define SLOG(oldStyle, slogCall) \
228 #else // No structured logging (e.g. auth)
229 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
230 #define SLOG(oldStyle, slogCall) \