]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dolog.hh
dnsdist: Capitalize the priority value in log messages
[thirdparty/pdns.git] / pdns / dolog.hh
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
64e4ebb4 22#pragma once
7754e68d 23#include <array>
4935d3ca 24#include <fstream>
86e28d2d 25#include <iomanip>
64e4ebb4 26#include <iostream>
4935d3ca 27#include <optional>
64e4ebb4 28#include <sstream>
927df82c 29#include "config.h"
6f4d5e75 30#if !defined(RECURSOR)
64e4ebb4 31#include <syslog.h>
6f4d5e75
O
32#else
33#include "logger.hh"
34#endif // RECURSOR
35
64e4ebb4 36/* This file is intended not to be metronome specific, and is simple example of C++2011
37 variadic templates in action.
38
86e28d2d 39 The goal is rapid easy to use logging to console & syslog.
64e4ebb4 40
86e28d2d 41 Usage:
64e4ebb4 42 string address="localhost";
fb7f8ec3 43 vinfolog("Got TCP connection from %s", remote);
64e4ebb4 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));
47
9c9b4998 48 Will log to stdout. Will syslog in any case with LOG_INFO,
fb7f8ec3 49 LOG_WARNING, LOG_ERR respectively. If g_verbose=false, vinfolog is a noop.
64e4ebb4 50 More generically, dolog(someiostream, "Hello %s", stream) will log to someiostream
51
52 This will happily print a string to %d! Doesn't do further format processing.
53*/
86e28d2d 54template <typename O>
7754e68d 55inline void dolog(O& outputStream, const char* str)
64e4ebb4 56{
7754e68d 57 outputStream << str;
64e4ebb4 58}
59
86e28d2d 60template <typename O, typename T, typename... Args>
7754e68d 61void dolog(O& outputStream, const char* formatStr, T value, const Args&... args)
64e4ebb4 62{
7754e68d
RG
63 while (*formatStr) {
64 if (*formatStr == '%') {
65 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
66 if (*(formatStr + 1) == '%') {
67 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
86e28d2d 68 ++formatStr;
64e4ebb4 69 }
70 else {
86e28d2d 71 outputStream << value;
7754e68d 72 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
86e28d2d
RG
73 formatStr += 2;
74 dolog(outputStream, formatStr, args...);
75 return;
64e4ebb4 76 }
77 }
7754e68d
RG
78 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
79 outputStream << *formatStr++;
6f4d5e75 80 }
64e4ebb4 81}
82
7754e68d 83#if !defined(RECURSOR)
86e28d2d 84// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
64e4ebb4 85extern bool g_verbose;
86e28d2d 86
927df82c 87#ifdef DNSDIST
86e28d2d
RG
88namespace dnsdist::logging
89{
90class LoggingConfiguration
91{
92public:
93 enum class TimeFormat
94 {
95 Numeric,
96 ISO8601
97 };
98
99 static void setVerbose(bool value = true)
100 {
101 g_verbose = value;
102 }
103 static void setSyslog(bool value = true)
104 {
105 s_syslog = value;
106 }
107 static void setStructuredLogging(bool value = true, std::string levelPrefix = "")
108 {
109 s_structuredLogging = value;
110 if (value) {
111 s_structuredLevelPrefix = levelPrefix.empty() ? "prio" : std::move(levelPrefix);
112 }
113 }
114 static void setLogTimestamps(bool value = true)
115 {
116 s_logTimestamps = value;
117 }
118 static void setStructuredTimeFormat(TimeFormat format)
119 {
120 s_structuredTimeFormat = format;
121 }
122 static void setVerboseStream(std::ofstream&& stream)
123 {
124 s_verboseStream = std::move(stream);
125 }
126 static bool getVerbose()
127 {
128 return g_verbose;
129 }
130 static bool getSyslog()
131 {
132 return s_syslog;
133 }
134 static bool getLogTimestamps()
135 {
136 return s_logTimestamps;
137 }
138 static std::optional<std::ofstream>& getVerboseStream()
139 {
140 return s_verboseStream;
141 }
142 static bool getStructuredLogging()
143 {
144 return s_structuredLogging;
145 }
146 static const std::string& getStructuredLoggingLevelPrefix()
147 {
148 return s_structuredLevelPrefix;
149 }
150
151 static TimeFormat getStructuredLoggingTimeFormat()
152 {
153 return s_structuredTimeFormat;
154 }
155
156private:
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;
163};
164
165extern void logTime(std::ostream& stream);
166}
927df82c 167#endif
64e4ebb4 168
0ca6a67f
RG
169inline void setSyslogFacility(int facility)
170{
171 /* we always call openlog() right away at startup */
172 closelog();
86e28d2d
RG
173 openlog("dnsdist", LOG_PID | LOG_NDELAY, facility);
174}
175
176namespace
177{
178inline const char* syslogLevelToStr(int level)
179{
180 static constexpr std::array levelStrs{
f7625f60
RG
181 "Emergency",
182 "Alert",
183 "Critical",
184 "Error",
185 "Warning",
186 "Notice",
187 "Info",
188 "Debug"};
86e28d2d
RG
189 return levelStrs.at(level);
190}
0ca6a67f
RG
191}
192
86e28d2d
RG
193template <typename... Args>
194void genlog(std::ostream& stream, [[maybe_unused]] int level, [[maybe_unused]] bool skipSyslog, const char* formatStr, const Args&... args)
64e4ebb4 195{
196 std::ostringstream str;
7754e68d 197 dolog(str, formatStr, args...);
927df82c 198
996fd9d2
RG
199 auto output = str.str();
200
86e28d2d
RG
201#ifdef DNSDIST
202 if (!skipSyslog && dnsdist::logging::LoggingConfiguration::getSyslog()) {
7754e68d 203 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): syslog is what it is
996fd9d2
RG
204 syslog(level, "%s", output.c_str());
205 }
927df82c 206
86e28d2d
RG
207 if (dnsdist::logging::LoggingConfiguration::getLogTimestamps()) {
208 dnsdist::logging::logTime(stream);
927df82c 209 }
927df82c 210
86e28d2d
RG
211 if (dnsdist::logging::LoggingConfiguration::getStructuredLogging()) {
212 stream << dnsdist::logging::LoggingConfiguration::getStructuredLoggingLevelPrefix() << "=\"" << syslogLevelToStr(level) << "\" ";
213 stream << "msg=" << std::quoted(output) << std::endl;
214 }
215 else {
216 stream << output << std::endl;
217 }
218#else
7754e68d 219 stream << output << std::endl;
86e28d2d 220#endif
64e4ebb4 221}
222
86e28d2d 223template <typename... Args>
7754e68d 224void verboselog(const char* formatStr, const Args&... args)
37a8e048 225{
bc5f8799 226#ifdef DNSDIST
86e28d2d
RG
227 if (auto& stream = dnsdist::logging::LoggingConfiguration::getVerboseStream()) {
228 genlog(*stream, LOG_DEBUG, true, formatStr, args...);
4935d3ca
RG
229 }
230 else {
bc5f8799 231#endif /* DNSDIST */
86e28d2d 232 genlog(std::cout, LOG_DEBUG, false, formatStr, args...);
bc5f8799 233#ifdef DNSDIST
4935d3ca 234 }
bc5f8799 235#endif /* DNSDIST */
37a8e048 236}
b2ad6825 237
86e28d2d
RG
238#define vinfolog \
239 if (g_verbose) \
240 verboselog
b2ad6825 241
86e28d2d 242template <typename... Args>
7754e68d 243void infolog(const char* formatStr, const Args&... args)
64e4ebb4 244{
86e28d2d 245 genlog(std::cout, LOG_INFO, false, formatStr, args...);
64e4ebb4 246}
247
86e28d2d 248template <typename... Args>
7754e68d 249void warnlog(const char* formatStr, const Args&... args)
64e4ebb4 250{
86e28d2d 251 genlog(std::cout, LOG_WARNING, false, formatStr, args...);
64e4ebb4 252}
253
86e28d2d 254template <typename... Args>
7754e68d 255void errlog(const char* formatStr, const Args&... args)
64e4ebb4 256{
86e28d2d 257 genlog(std::cout, LOG_ERR, false, formatStr, args...);
64e4ebb4 258}
b2ad6825 259
6f4d5e75 260#else // RECURSOR
6f4d5e75 261#define g_verbose 0
86e28d2d
RG
262#define vinfolog \
263 if (g_verbose) \
264 infolog
6f4d5e75 265
86e28d2d 266template <typename... Args>
7754e68d 267void infolog(const char* formatStr, const Args&... args)
6f4d5e75 268{
7754e68d
RG
269 g_log << Logger::Info;
270 dolog(g_log, formatStr, args...);
6f4d5e75
O
271}
272
86e28d2d 273template <typename... Args>
7754e68d 274void warnlog(const char* formatStr, const Args&... args)
6f4d5e75 275{
7754e68d
RG
276 g_log << Logger::Warning;
277 dolog(g_log, formatStr, args...);
6f4d5e75
O
278}
279
86e28d2d 280template <typename... Args>
7754e68d 281void errlog(const char* formatStr, const Args&... args)
6f4d5e75 282{
7754e68d
RG
283 g_log << Logger::Error;
284 dolog(g_log, formatStr, args...);
6f4d5e75
O
285}
286
287#endif