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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <mutex>
27
28 #include "logger.hh"
29 #include "misc.hh"
30 #ifndef RECURSOR
31 #include "statbag.hh"
32 extern StatBag S;
33 #endif
34 #include "namespaces.hh"
35
36 thread_local Logger::PerThread Logger::t_perThread;
37
getLogger()38 Logger& getLogger()
39 {
40 /* Since the Logger can be called very early, we need to make sure
41 that the relevant parts are initialized no matter what, which is tricky
42 because we can't easily control the initialization order, especially with
43 built-in backends.
44 t_perThread is thread_local, so it will be initialized when first accessed,
45 but we need to make sure that the object itself is initialized, and making
46 it a function-level static variable achieves that, because it will be
47 initialized the first time we enter this function at the very last.
48 */
49 static Logger log("", LOG_DAEMON);
50 return log;
51 }
52
log(const string & msg,Urgency u)53 void Logger::log(const string &msg, Urgency u) noexcept
54 {
55 #ifndef RECURSOR
56 bool mustAccount(false);
57 #endif
58 if(u<=consoleUrgency) {
59 char buffer[50] = "";
60 if (d_timestamps) {
61 struct tm tm;
62 time_t t;
63 time(&t);
64 localtime_r(&t, &tm);
65 strftime(buffer,sizeof(buffer),"%b %d %H:%M:%S ", &tm);
66 }
67
68 string prefix;
69 if (d_prefixed) {
70 switch(u) {
71 case All:
72 prefix = "[all] ";
73 break;
74 case Alert:
75 prefix = "[ALERT] ";
76 break;
77 case Critical:
78 prefix = "[CRITICAL] ";
79 break;
80 case Error:
81 prefix = "[ERROR] ";
82 break;
83 case Warning:
84 prefix = "[WARNING] ";
85 break;
86 case Notice:
87 prefix = "[NOTICE] ";
88 break;
89 case Info:
90 prefix = "[INFO] ";
91 break;
92 case Debug:
93 prefix = "[DEBUG] ";
94 break;
95 case None:
96 prefix = "[none] ";
97 break;
98 }
99 }
100
101 static std::mutex m;
102 std::lock_guard<std::mutex> l(m); // the C++-2011 spec says we need this, and OSX actually does
103 clog << string(buffer) + prefix + msg <<endl;
104 #ifndef RECURSOR
105 mustAccount=true;
106 #endif
107 }
108 if( u <= d_loglevel && !d_disableSyslog ) {
109 syslog(u,"%s",msg.c_str());
110 #ifndef RECURSOR
111 mustAccount=true;
112 #endif
113 }
114
115 #ifndef RECURSOR
116 if(mustAccount) {
117 try {
118 S.ringAccount("logmessages",msg);
119 }
120 catch (const runtime_error& e) {
121 cerr << e.what() << endl;
122 }
123 }
124 #endif
125 }
126
setLoglevel(Urgency u)127 void Logger::setLoglevel( Urgency u )
128 {
129 d_loglevel = u;
130 }
131
132
toConsole(Urgency u)133 void Logger::toConsole(Urgency u)
134 {
135 consoleUrgency=u;
136 }
137
open()138 void Logger::open()
139 {
140 if(opened)
141 closelog();
142 openlog(name.c_str(),flags,d_facility);
143 opened=true;
144 }
145
setName(const string & _name)146 void Logger::setName(const string &_name)
147 {
148 name=_name;
149 open();
150 }
151
Logger(string n,int facility)152 Logger::Logger(string n, int facility) :
153 name(std::move(n)), flags(LOG_PID|LOG_NDELAY), d_facility(facility), d_loglevel(Logger::None),
154 consoleUrgency(Error), opened(false), d_disableSyslog(false)
155 {
156 open();
157
158 }
159
operator <<(Urgency u)160 Logger& Logger::operator<<(Urgency u)
161 {
162 getPerThread().d_urgency=u;
163 return *this;
164 }
165
getPerThread()166 Logger::PerThread& Logger::getPerThread()
167 {
168 return t_perThread;
169 }
170
operator <<(const string & s)171 Logger& Logger::operator<<(const string &s)
172 {
173 PerThread& pt = getPerThread();
174 pt.d_output.append(s);
175 return *this;
176 }
177
operator <<(const char * s)178 Logger& Logger::operator<<(const char *s)
179 {
180 *this<<string(s);
181 return *this;
182 }
183
operator <<(ostream & (&)(ostream &))184 Logger& Logger::operator<<(ostream & (&)(ostream &))
185 {
186 PerThread& pt = getPerThread();
187
188 log(pt.d_output, pt.d_urgency);
189 pt.d_output.clear();
190 pt.d_urgency=Info;
191 return *this;
192 }
193
operator <<(const DNSName & d)194 Logger& Logger::operator<<(const DNSName &d)
195 {
196 *this<<d.toLogString();
197
198 return *this;
199 }
200
operator <<(const ComboAddress & ca)201 Logger& Logger::operator<<(const ComboAddress &ca)
202 {
203 *this<<ca.toLogString();
204 return *this;
205 }
206
207