Mercurial > irccd
annotate common/logger.cpp @ 419:6ae7f069ba51 release-2.0
Close release-2.0 branch
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 01 Feb 2017 11:54:10 +0100 |
parents | 03068f5ed79d |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * logger.cpp -- irccd logging | |
3 * | |
4 * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <cerrno> | |
20 #include <cstring> | |
21 #include <fstream> | |
22 #include <iostream> | |
23 #include <stdexcept> | |
24 #include <streambuf> | |
25 | |
26 #include <irccd-config.h> | |
27 | |
28 #if defined(HAVE_SYSLOG) | |
29 # include <syslog.h> | |
30 #endif // !HAVE_SYSLOG | |
31 | |
32 #include "logger.h" | |
33 #include "system.h" | |
34 | |
35 namespace irccd { | |
36 | |
37 namespace log { | |
38 | |
39 /* -------------------------------------------------------- | |
40 * Buffer -- output buffer (private) | |
41 * -------------------------------------------------------- */ | |
42 | |
43 /** | |
44 * @class LoggerBuffer | |
45 * @brief This class is a internal buffer for the Logger streams | |
46 */ | |
47 class Buffer : public std::stringbuf { | |
48 private: | |
49 Interface *m_interface{nullptr}; | |
50 Level m_level; | |
51 | |
52 public: | |
53 /** | |
54 * Create the buffer with the specified level. | |
55 * | |
56 * @param level the level | |
57 */ | |
58 inline Buffer(Level level) noexcept | |
23
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
59 : m_level(level) |
0 | 60 { |
61 } | |
62 | |
63 /** | |
64 * Update the underlying interface. | |
65 * | |
66 * @param iface is a non-owning pointer to the new interface | |
67 */ | |
68 inline void setInterface(Interface *iface) noexcept | |
69 { | |
70 m_interface = iface; | |
71 } | |
72 | |
73 /** | |
74 * Sync the buffer by calling the interface if set. | |
75 * | |
76 * This function split the buffer line per line and remove it before | |
77 * calling the appropriate interface function. | |
78 */ | |
79 virtual int sync() override | |
80 { | |
81 #if defined(NDEBUG) | |
82 /* | |
83 * Debug is disabled, don't call interface->write() but don't | |
84 * forget to flush the buffer. | |
85 */ | |
86 if (m_level == Level::Debug) { | |
87 str(""); | |
88 | |
89 return 0; | |
90 } | |
91 #endif | |
92 | |
93 /* Verbose is disabled? Don't show and flush the buffer too. */ | |
94 if (m_level == Level::Info && !isVerbose()) { | |
95 str(""); | |
96 | |
97 return 0; | |
98 } | |
99 | |
100 std::string buffer = str(); | |
101 std::string::size_type pos; | |
102 | |
103 while ((pos = buffer.find("\n")) != std::string::npos) { | |
104 std::string line = buffer.substr(0, pos); | |
105 | |
106 /* Remove this line */ | |
107 buffer.erase(buffer.begin(), buffer.begin() + pos + 1); | |
108 | |
109 if (m_interface) | |
110 m_interface->write(m_level, line); | |
111 } | |
112 | |
113 str(buffer); | |
114 | |
115 return 0; | |
116 } | |
117 }; | |
118 | |
119 /* -------------------------------------------------------- | |
120 * Local variables | |
121 * -------------------------------------------------------- */ | |
122 | |
123 namespace { | |
124 | |
125 /* Generic interface for all outputs */ | |
126 std::unique_ptr<Interface> iface; | |
127 | |
128 /* Internal buffers */ | |
23
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
129 Buffer bufferInfo(Level::Info); |
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
130 Buffer bufferWarning(Level::Warning); |
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
131 Buffer bufferDebug(Level::Debug); |
0 | 132 |
133 /* Stream outputs */ | |
23
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
134 std::ostream streamInfo(&bufferInfo); |
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
135 std::ostream streamWarning(&bufferWarning); |
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
136 std::ostream streamDebug(&bufferDebug); |
0 | 137 |
138 /* Options */ | |
23
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
139 bool verbose(false); |
0 | 140 |
141 } // !namespace | |
142 | |
143 /* -------------------------------------------------------- | |
144 * Console | |
145 * -------------------------------------------------------- */ | |
146 | |
147 void Console::write(Level level, const std::string &line) noexcept | |
148 { | |
149 if (level == Level::Warning) | |
150 std::cerr << line << std::endl; | |
151 else | |
152 std::cout << line << std::endl; | |
153 } | |
154 | |
155 /* -------------------------------------------------------- | |
156 * File | |
157 * -------------------------------------------------------- */ | |
158 | |
159 File::File(std::string normal, std::string errors) | |
23
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
160 : m_outputNormal(std::move(normal)) |
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
161 , m_outputError(std::move(errors)) |
0 | 162 { |
163 } | |
164 | |
165 void File::write(Level level, const std::string &line) noexcept | |
166 { | |
167 std::string &path = (level == Level::Warning) ? m_outputError : m_outputNormal; | |
168 std::ofstream output(path, std::ofstream::out | std::ofstream::app); | |
169 | |
170 output << line << std::endl; | |
171 } | |
172 | |
173 /* -------------------------------------------------------- | |
174 * Silent | |
175 * -------------------------------------------------------- */ | |
176 | |
177 void Silent::write(Level, const std::string &) noexcept | |
178 { | |
179 } | |
180 | |
181 /* -------------------------------------------------------- | |
182 * Syslog | |
183 * -------------------------------------------------------- */ | |
184 | |
185 #if defined(HAVE_SYSLOG) | |
186 | |
187 Syslog::Syslog() | |
188 { | |
189 openlog(sys::programName().c_str(), LOG_PID, LOG_DAEMON); | |
190 } | |
191 | |
192 Syslog::~Syslog() | |
193 { | |
194 closelog(); | |
195 } | |
196 | |
197 void Syslog::write(Level level, const std::string &line) noexcept | |
198 { | |
199 int syslogLevel; | |
200 | |
201 switch (level) { | |
202 case Level::Warning: | |
203 syslogLevel = LOG_WARNING; | |
204 break; | |
205 case Level::Debug: | |
206 syslogLevel = LOG_DEBUG; | |
207 break; | |
208 case Level::Info: | |
209 /* FALLTHROUGH */ | |
210 default: | |
211 syslogLevel = LOG_INFO; | |
212 break; | |
213 } | |
214 | |
215 syslog(syslogLevel | LOG_USER, "%s", line.c_str()); | |
216 } | |
217 | |
218 #endif // !HAVE_SYSLOG | |
219 | |
220 /* -------------------------------------------------------- | |
221 * Functions | |
222 * -------------------------------------------------------- */ | |
223 | |
224 void setInterface(std::unique_ptr<Interface> ifaceValue) noexcept | |
225 { | |
226 iface = std::move(ifaceValue); | |
227 bufferInfo.setInterface(iface.get()); | |
228 bufferWarning.setInterface(iface.get()); | |
229 bufferDebug.setInterface(iface.get()); | |
230 } | |
231 | |
232 std::ostream &info() noexcept | |
233 { | |
234 return streamInfo; | |
235 } | |
236 | |
237 std::ostream &warning() noexcept | |
238 { | |
239 return streamWarning; | |
240 } | |
241 | |
242 std::ostream &debug() noexcept | |
243 { | |
244 return streamDebug; | |
245 } | |
246 | |
247 bool isVerbose() noexcept | |
248 { | |
249 return verbose; | |
250 } | |
251 | |
252 void setVerbose(bool mode) noexcept | |
253 { | |
254 verbose = mode; | |
255 } | |
256 | |
257 } // !log | |
258 | |
259 } // !irccd |