]>
Commit | Line | Data |
---|---|---|
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 | 54 | template <typename O> |
7754e68d | 55 | inline void dolog(O& outputStream, const char* str) |
64e4ebb4 | 56 | { |
7754e68d | 57 | outputStream << str; |
64e4ebb4 | 58 | } |
59 | ||
86e28d2d | 60 | template <typename O, typename T, typename... Args> |
7754e68d | 61 | void 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 | 85 | extern bool g_verbose; |
86e28d2d | 86 | |
927df82c | 87 | #ifdef DNSDIST |
86e28d2d RG |
88 | namespace dnsdist::logging |
89 | { | |
90 | class LoggingConfiguration | |
91 | { | |
92 | public: | |
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 | ||
156 | private: | |
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 | ||
165 | extern void logTime(std::ostream& stream); | |
166 | } | |
927df82c | 167 | #endif |
64e4ebb4 | 168 | |
0ca6a67f RG |
169 | inline 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 | ||
176 | namespace | |
177 | { | |
178 | inline const char* syslogLevelToStr(int level) | |
179 | { | |
180 | static constexpr std::array levelStrs{ | |
181 | "emergency", | |
182 | "alert", | |
183 | "critical", | |
184 | "error", | |
185 | "warning", | |
186 | "notice", | |
187 | "info", | |
188 | "debug"}; | |
189 | return levelStrs.at(level); | |
190 | } | |
0ca6a67f RG |
191 | } |
192 | ||
86e28d2d RG |
193 | template <typename... Args> |
194 | void 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 | 223 | template <typename... Args> |
7754e68d | 224 | void 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 | 242 | template <typename... Args> |
7754e68d | 243 | void infolog(const char* formatStr, const Args&... args) |
64e4ebb4 | 244 | { |
86e28d2d | 245 | genlog(std::cout, LOG_INFO, false, formatStr, args...); |
64e4ebb4 | 246 | } |
247 | ||
86e28d2d | 248 | template <typename... Args> |
7754e68d | 249 | void warnlog(const char* formatStr, const Args&... args) |
64e4ebb4 | 250 | { |
86e28d2d | 251 | genlog(std::cout, LOG_WARNING, false, formatStr, args...); |
64e4ebb4 | 252 | } |
253 | ||
86e28d2d | 254 | template <typename... Args> |
7754e68d | 255 | void 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 | 266 | template <typename... Args> |
7754e68d | 267 | void 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 | 273 | template <typename... Args> |
7754e68d | 274 | void 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 | 280 | template <typename... Args> |
7754e68d | 281 | void 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 |