]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/logger.hh
Merge pull request #14020 from omoerbeek/rec-compiling-rust-dcos
[thirdparty/pdns.git] / pdns / logger.hh
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 */
22 #pragma once
23
24 #include <string>
25 #include <ctime>
26 #include <iostream>
27 #include <optional>
28 #include <sstream>
29 #include <variant>
30 #include <syslog.h>
31
32 #include "namespaces.hh"
33 #include "dnsname.hh"
34 #include "iputils.hh"
35
36 //! The Logger class can be used to log messages in various ways.
37 class Logger
38 {
39 public:
40 Logger(string, int facility = LOG_DAEMON); //!< pass the identification you wish to appear in the log
41
42 //! The urgency of a log message
43 enum Urgency
44 {
45 All = 32767,
46 Alert = LOG_ALERT,
47 Critical = LOG_CRIT,
48 Error = LOG_ERR,
49 Warning = LOG_WARNING,
50 Notice = LOG_NOTICE,
51 Info = LOG_INFO,
52 Debug = LOG_DEBUG,
53 None = -1
54 };
55
56 /** Log a message.
57 \param msg Message you wish to log
58 \param u Urgency of the message you wish to log
59 */
60 void log(const string& msg, Urgency u = Notice) noexcept;
61
62 void setFacility(int f)
63 {
64 d_facility = f;
65 open();
66 } //!< Choose logging facility
67 void setFlag(int f)
68 {
69 flags |= f;
70 open();
71 } //!< set a syslog flag
72 void setName(const string&);
73
74 //! set lower limit of urgency needed for console display. Messages of this urgency, and higher, will be displayed
75 void toConsole(Urgency);
76 void setLoglevel(Urgency);
77
78 void disableSyslog(bool d)
79 {
80 d_disableSyslog = d;
81 }
82
83 void setTimestamps(bool t)
84 {
85 d_timestamps = t;
86 }
87
88 void setPrefixed(bool p)
89 {
90 d_prefixed = p;
91 }
92
93 //! Log to a file.
94 void toFile(const string& filename);
95
96 void resetFlags()
97 {
98 flags = 0;
99 open();
100 } //!< zero the flags
101 /** Use this to stream to your log, like this:
102 \code
103 g_log<<"This is an informational message"<<endl; // logged at default loglevel (Info)
104 g_log<<Logger::Warning<<"Out of diskspace"<<endl; // Logged as a warning
105 g_log<<"This is an informational message"<<endl; // logged AGAIN at default loglevel (Info)
106 \endcode
107 */
108 Logger& operator<<(const char* s);
109 Logger& operator<<(const string& s); //!< log a string
110 Logger& operator<<(const DNSName&);
111 Logger& operator<<(const ComboAddress&); //!< log an address
112 Logger& operator<<(Urgency); //!< set the urgency, << style
113
114 Logger& operator<<(const QType& qtype)
115 {
116 *this << qtype.toString();
117 return *this;
118 }
119
120 Logger& operator<<(const QClass& qclass)
121 {
122 *this << qclass.toString();
123 return *this;
124 }
125
126 // Using const & since otherwise SyncRes:: values induce (illegal) copies
127 template <typename T>
128 Logger& operator<<(const T& i)
129 {
130 ostringstream tmp;
131 tmp << i;
132 *this << tmp.str();
133 return *this;
134 }
135
136 Logger& operator<<(std::ostream& (&)(std::ostream&)); //!< this is to recognise the endl, and to commit the log
137
138 private:
139 struct PerThread
140 {
141 PerThread() :
142 d_urgency(Info)
143 {}
144 string d_output;
145 Urgency d_urgency;
146 };
147 PerThread& getPerThread();
148 void open();
149
150 static thread_local PerThread t_perThread;
151 string name;
152 int flags;
153 int d_facility;
154 Urgency d_loglevel;
155 Urgency consoleUrgency;
156 bool opened;
157 bool d_disableSyslog;
158 bool d_timestamps{true};
159 bool d_prefixed{false}; // this used to prefix the loglevel, but now causes formatting like structured logging
160 };
161
162 Logger& getLogger();
163
164 #define g_log getLogger()
165
166 #ifdef VERBOSELOG
167 #define DLOG(x) x
168 #else
169 #define DLOG(x) ((void)0)
170 #endif
171
172 // The types below are used by rec, which can log to g_log (general logging) or a string stream
173 // (trace-regexp). We pass an OptLog object to the code that should not know anything about this
174 // That code should then log using VLOG
175
176 struct LogVariant
177 {
178 string prefix;
179 timeval start;
180 // variant cannot hold references directly, use a wrapper
181 std::variant<std::reference_wrapper<Logger>, std::reference_wrapper<ostringstream>> v;
182 };
183
184 using OptLog = std::optional<LogVariant>;
185
186 void addTraceTS(const timeval& start, ostringstream& str);
187
188 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
189 #define VLOG(log, x) \
190 if (log) { \
191 if (std::holds_alternative<std::reference_wrapper<Logger>>((log)->v)) { \
192 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
193 std::get<std::reference_wrapper<Logger>>((log)->v).get() << Logger::Warning << (log)->prefix << x; \
194 } \
195 else if (std::holds_alternative<std::reference_wrapper<ostringstream>>((log)->v)) { \
196 addTraceTS((log)->start, std::get<std::reference_wrapper<ostringstream>>((log)->v).get()); \
197 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
198 std::get<std::reference_wrapper<ostringstream>>((log)->v).get() << (log)->prefix << x; \
199 } \
200 }
201
202 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
203 #define VLOG_NO_PREFIX(log, x) \
204 if (log) { \
205 if (std::holds_alternative<std::reference_wrapper<Logger>>((log)->v)) { \
206 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
207 std::get<std::reference_wrapper<Logger>>((log)->v).get() << Logger::Warning << x; \
208 } \
209 else if (std::holds_alternative<std::reference_wrapper<ostringstream>>((log)->v)) { \
210 addTraceTS((log)->start, std::get<std::reference_wrapper<ostringstream>>((log)->v).get()); \
211 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
212 std::get<std::reference_wrapper<ostringstream>>((log)->v).get() << x; \
213 } \
214 }