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.
30 #if !defined(RECURSOR)
36 /* This file is intended not to be metronome specific, and is simple example of C++2011
37 variadic templates in action.
39 The goal is rapid easy to use logging to console & syslog.
42 string address="localhost";
43 vinfolog("Got TCP connection from %s", remote);
44 infolog("Bound to %s port %d", address, port);
45 warnlog("Query took %d milliseconds", 1232.4); // yes, %d
46 errlog("Unable to bind to %s: %s", ca.toStringWithPort(), strerr(errno));
48 Will log to stdout. Will syslog in any case with LOG_INFO,
49 LOG_WARNING, LOG_ERR respectively. If g_verbose=false, vinfolog is a noop.
50 More generically, dolog(someiostream, "Hello %s", stream) will log to someiostream
52 This will happily print a string to %d! Doesn't do further format processing.
55 inline void dolog(O& outputStream, const char* str)
60 template <typename O, typename T, typename... Args>
61 void dolog(O& outputStream, const char* formatStr, T value, const Args&... args)
64 if (*formatStr == '%') {
65 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
66 if (*(formatStr + 1) == '%') {
67 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
71 outputStream << value;
72 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
74 dolog(outputStream, formatStr, args...);
78 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
79 outputStream << *formatStr++;
83 #if !defined(RECURSOR)
84 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
85 extern bool g_verbose;
88 namespace dnsdist::logging
90 class LoggingConfiguration
99 static void setVerbose(bool value = true)
103 static void setSyslog(bool value = true)
107 static void setStructuredLogging(bool value = true, std::string levelPrefix = "")
109 s_structuredLogging = value;
111 s_structuredLevelPrefix = levelPrefix.empty() ? "prio" : std::move(levelPrefix);
114 static void setLogTimestamps(bool value = true)
116 s_logTimestamps = value;
118 static void setStructuredTimeFormat(TimeFormat format)
120 s_structuredTimeFormat = format;
122 static void setVerboseStream(std::ofstream&& stream)
124 s_verboseStream = std::move(stream);
126 static bool getVerbose()
130 static bool getSyslog()
134 static bool getLogTimestamps()
136 return s_logTimestamps;
138 static std::optional<std::ofstream>& getVerboseStream()
140 return s_verboseStream;
142 static bool getStructuredLogging()
144 return s_structuredLogging;
146 static const std::string& getStructuredLoggingLevelPrefix()
148 return s_structuredLevelPrefix;
151 static TimeFormat getStructuredLoggingTimeFormat()
153 return s_structuredTimeFormat;
157 static std::optional<std::ofstream> s_verboseStream;
158 static std::string s_structuredLevelPrefix;
159 static TimeFormat s_structuredTimeFormat;
160 static bool s_structuredLogging;
161 static bool s_logTimestamps;
162 static bool s_syslog;
165 extern void logTime(std::ostream& stream);
169 inline void setSyslogFacility(int facility)
171 /* we always call openlog() right away at startup */
173 openlog("dnsdist", LOG_PID | LOG_NDELAY, facility);
178 inline const char* syslogLevelToStr(int level)
180 static constexpr std::array levelStrs{
189 return levelStrs.at(level);
193 template <typename... Args>
194 void genlog(std::ostream& stream, [[maybe_unused]] int level, [[maybe_unused]] bool skipSyslog, const char* formatStr, const Args&... args)
196 std::ostringstream str;
197 dolog(str, formatStr, args...);
199 auto output = str.str();
202 if (!skipSyslog && dnsdist::logging::LoggingConfiguration::getSyslog()) {
203 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): syslog is what it is
204 syslog(level, "%s", output.c_str());
207 if (dnsdist::logging::LoggingConfiguration::getLogTimestamps()) {
208 dnsdist::logging::logTime(stream);
211 if (dnsdist::logging::LoggingConfiguration::getStructuredLogging()) {
212 stream << dnsdist::logging::LoggingConfiguration::getStructuredLoggingLevelPrefix() << "=\"" << syslogLevelToStr(level) << "\" ";
213 stream << "msg=" << std::quoted(output) << std::endl;
216 stream << output << std::endl;
219 stream << output << std::endl;
223 template <typename... Args>
224 void verboselog(const char* formatStr, const Args&... args)
227 if (auto& stream = dnsdist::logging::LoggingConfiguration::getVerboseStream()) {
228 genlog(*stream, LOG_DEBUG, true, formatStr, args...);
232 genlog(std::cout, LOG_DEBUG, false, formatStr, args...);
242 template <typename... Args>
243 void infolog(const char* formatStr, const Args&... args)
245 genlog(std::cout, LOG_INFO, false, formatStr, args...);
248 template <typename... Args>
249 void warnlog(const char* formatStr, const Args&... args)
251 genlog(std::cout, LOG_WARNING, false, formatStr, args...);
254 template <typename... Args>
255 void errlog(const char* formatStr, const Args&... args)
257 genlog(std::cout, LOG_ERR, false, formatStr, args...);
266 template <typename... Args>
267 void infolog(const char* formatStr, const Args&... args)
269 g_log << Logger::Info;
270 dolog(g_log, formatStr, args...);
273 template <typename... Args>
274 void warnlog(const char* formatStr, const Args&... args)
276 g_log << Logger::Warning;
277 dolog(g_log, formatStr, args...);
280 template <typename... Args>
281 void errlog(const char* formatStr, const Args&... args)
283 g_log << Logger::Error;
284 dolog(g_log, formatStr, args...);