1 | // |
2 | // Logger.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Logging |
6 | // Module: Logger |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Logger.h" |
16 | #include "Poco/Formatter.h" |
17 | #include "Poco/LoggingRegistry.h" |
18 | #include "Poco/Exception.h" |
19 | #include "Poco/NumberFormatter.h" |
20 | #include "Poco/NumberParser.h" |
21 | #include "Poco/String.h" |
22 | |
23 | |
24 | namespace Poco { |
25 | |
26 | |
27 | Logger::Logger(const std::string& name, Channel::Ptr pChannel, int level): _name(name), _pChannel(pChannel), _level(level) |
28 | { |
29 | } |
30 | |
31 | |
32 | Logger::~Logger() |
33 | { |
34 | } |
35 | |
36 | |
37 | void Logger::setChannel(Channel::Ptr pChannel) |
38 | { |
39 | _pChannel = pChannel; |
40 | } |
41 | |
42 | |
43 | Channel::Ptr Logger::getChannel() const |
44 | { |
45 | return _pChannel; |
46 | } |
47 | |
48 | |
49 | void Logger::setLevel(int level) |
50 | { |
51 | _level = level; |
52 | } |
53 | |
54 | |
55 | void Logger::setLevel(const std::string& level) |
56 | { |
57 | setLevel(parseLevel(level)); |
58 | } |
59 | |
60 | |
61 | void Logger::setProperty(const std::string& rName, const std::string& rValue) |
62 | { |
63 | if (rName == "channel" ) |
64 | setChannel(LoggingRegistry::defaultRegistry().channelForName(rValue)); |
65 | else if (rName == "level" ) |
66 | setLevel(rValue); |
67 | else |
68 | Channel::setProperty(rName, rValue); |
69 | } |
70 | |
71 | |
72 | void Logger::log(const Message& msg) |
73 | { |
74 | if (_level >= msg.getPriority() && _pChannel) |
75 | { |
76 | _pChannel->log(msg); |
77 | } |
78 | } |
79 | |
80 | |
81 | void Logger::log(const Exception& exc) |
82 | { |
83 | error(exc.displayText()); |
84 | } |
85 | |
86 | |
87 | void Logger::log(const Exception& exc, const char* file, int line) |
88 | { |
89 | error(exc.displayText(), file, line); |
90 | } |
91 | |
92 | |
93 | void Logger::dump(const std::string& msg, const void* buffer, std::size_t length, Message::Priority prio) |
94 | { |
95 | if (_level >= prio && _pChannel) |
96 | { |
97 | std::string text(msg); |
98 | formatDump(text, buffer, length); |
99 | _pChannel->log(Message(_name, text, prio)); |
100 | } |
101 | } |
102 | |
103 | |
104 | void Logger::setLevel(const std::string& name, int level) |
105 | { |
106 | Mutex::ScopedLock lock(_mapMtx); |
107 | |
108 | if (_pLoggerMap) |
109 | { |
110 | std::string::size_type len = name.length(); |
111 | for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it) |
112 | { |
113 | if (len == 0 || |
114 | (it->first.compare(0, len, name) == 0 && (it->first.length() == len || it->first[len] == '.'))) |
115 | { |
116 | it->second->setLevel(level); |
117 | } |
118 | } |
119 | } |
120 | } |
121 | |
122 | |
123 | void Logger::setChannel(const std::string& name, Channel::Ptr pChannel) |
124 | { |
125 | Mutex::ScopedLock lock(_mapMtx); |
126 | |
127 | if (_pLoggerMap) |
128 | { |
129 | std::string::size_type len = name.length(); |
130 | for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it) |
131 | { |
132 | if (len == 0 || |
133 | (it->first.compare(0, len, name) == 0 && (it->first.length() == len || it->first[len] == '.'))) |
134 | { |
135 | it->second->setChannel(pChannel); |
136 | } |
137 | } |
138 | } |
139 | } |
140 | |
141 | |
142 | void Logger::setProperty(const std::string& loggerName, const std::string& propertyName, const std::string& value) |
143 | { |
144 | Mutex::ScopedLock lock(_mapMtx); |
145 | |
146 | if (_pLoggerMap) |
147 | { |
148 | std::string::size_type len = loggerName.length(); |
149 | for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it) |
150 | { |
151 | if (len == 0 || |
152 | (it->first.compare(0, len, loggerName) == 0 && (it->first.length() == len || it->first[len] == '.'))) |
153 | { |
154 | it->second->setProperty(propertyName, value); |
155 | } |
156 | } |
157 | } |
158 | } |
159 | |
160 | |
161 | std::string Logger::format(const std::string& fmt, const std::string& arg) |
162 | { |
163 | std::string args[] = |
164 | { |
165 | arg |
166 | }; |
167 | return format(fmt, 1, args); |
168 | } |
169 | |
170 | |
171 | std::string Logger::format(const std::string& fmt, const std::string& arg0, const std::string& arg1) |
172 | { |
173 | std::string args[] = |
174 | { |
175 | arg0, |
176 | arg1 |
177 | }; |
178 | return format(fmt, 2, args); |
179 | } |
180 | |
181 | |
182 | std::string Logger::format(const std::string& fmt, const std::string& arg0, const std::string& arg1, const std::string& arg2) |
183 | { |
184 | std::string args[] = |
185 | { |
186 | arg0, |
187 | arg1, |
188 | arg2 |
189 | }; |
190 | return format(fmt, 3, args); |
191 | } |
192 | |
193 | |
194 | std::string Logger::format(const std::string& fmt, const std::string& arg0, const std::string& arg1, const std::string& arg2, const std::string& arg3) |
195 | { |
196 | std::string args[] = |
197 | { |
198 | arg0, |
199 | arg1, |
200 | arg2, |
201 | arg3 |
202 | }; |
203 | return format(fmt, 4, args); |
204 | } |
205 | |
206 | |
207 | std::string Logger::format(const std::string& fmt, int argc, std::string argv[]) |
208 | { |
209 | std::string result; |
210 | std::string::const_iterator it = fmt.begin(); |
211 | while (it != fmt.end()) |
212 | { |
213 | if (*it == '$') |
214 | { |
215 | ++it; |
216 | if (*it == '$') |
217 | { |
218 | result += '$'; |
219 | } |
220 | else if (*it >= '0' && *it <= '9') |
221 | { |
222 | int i = *it - '0'; |
223 | if (i < argc) |
224 | result += argv[i]; |
225 | } |
226 | else |
227 | { |
228 | result += '$'; |
229 | result += *it; |
230 | } |
231 | } |
232 | else result += *it; |
233 | ++it; |
234 | } |
235 | return result; |
236 | } |
237 | |
238 | |
239 | void Logger::(std::string& message, const void* buffer, std::size_t length) |
240 | { |
241 | const int BYTES_PER_LINE = 16; |
242 | |
243 | message.reserve(message.size() + length*6); |
244 | if (!message.empty()) message.append("\n" ); |
245 | unsigned char* base = (unsigned char*) buffer; |
246 | int addr = 0; |
247 | while (addr < length) |
248 | { |
249 | if (addr > 0) message.append("\n" ); |
250 | message.append(NumberFormatter::formatHex(addr, 4)); |
251 | message.append(" " ); |
252 | int offset = 0; |
253 | while (addr + offset < length && offset < BYTES_PER_LINE) |
254 | { |
255 | message.append(NumberFormatter::formatHex(base[addr + offset], 2)); |
256 | message.append(offset == 7 ? " " : " " ); |
257 | ++offset; |
258 | } |
259 | if (offset < 7) message.append(" " ); |
260 | while (offset < BYTES_PER_LINE) { message.append(" " ); ++offset; } |
261 | message.append(" " ); |
262 | offset = 0; |
263 | while (addr + offset < length && offset < BYTES_PER_LINE) |
264 | { |
265 | unsigned char c = base[addr + offset]; |
266 | message += (c >= 32 && c < 127) ? (char) c : '.'; |
267 | ++offset; |
268 | } |
269 | addr += BYTES_PER_LINE; |
270 | } |
271 | } |
272 | |
273 | |
274 | Logger& Logger::get(const std::string& name) |
275 | { |
276 | Mutex::ScopedLock lock(_mapMtx); |
277 | |
278 | return unsafeGet(name); |
279 | } |
280 | |
281 | |
282 | Logger& Logger::unsafeGet(const std::string& name) |
283 | { |
284 | Ptr pLogger = find(name); |
285 | if (!pLogger) |
286 | { |
287 | if (name == ROOT) |
288 | { |
289 | pLogger = new Logger(name, 0, Message::PRIO_INFORMATION); |
290 | } |
291 | else |
292 | { |
293 | Logger& par = parent(name); |
294 | pLogger = new Logger(name, par.getChannel(), par.getLevel()); |
295 | } |
296 | add(pLogger); |
297 | } |
298 | return *pLogger; |
299 | } |
300 | |
301 | |
302 | Logger& Logger::create(const std::string& name, Channel::Ptr pChannel, int level) |
303 | { |
304 | Mutex::ScopedLock lock(_mapMtx); |
305 | |
306 | if (find(name)) throw ExistsException(); |
307 | Ptr pLogger = new Logger(name, pChannel, level); |
308 | add(pLogger); |
309 | return *pLogger; |
310 | } |
311 | |
312 | |
313 | Logger& Logger::root() |
314 | { |
315 | Mutex::ScopedLock lock(_mapMtx); |
316 | |
317 | return unsafeGet(ROOT); |
318 | } |
319 | |
320 | |
321 | Logger::Ptr Logger::has(const std::string& name) |
322 | { |
323 | Mutex::ScopedLock lock(_mapMtx); |
324 | |
325 | return find(name); |
326 | } |
327 | |
328 | |
329 | void Logger::shutdown() |
330 | { |
331 | Mutex::ScopedLock lock(_mapMtx); |
332 | |
333 | _pLoggerMap.reset(); |
334 | } |
335 | |
336 | |
337 | Logger::Ptr Logger::find(const std::string& name) |
338 | { |
339 | if (_pLoggerMap) |
340 | { |
341 | LoggerMap::iterator it = _pLoggerMap->find(name); |
342 | if (it != _pLoggerMap->end()) return it->second; |
343 | } |
344 | return 0; |
345 | } |
346 | |
347 | |
348 | void Logger::destroy(const std::string& name) |
349 | { |
350 | Mutex::ScopedLock lock(_mapMtx); |
351 | |
352 | if (_pLoggerMap) |
353 | { |
354 | LoggerMap::iterator it = _pLoggerMap->find(name); |
355 | if (it != _pLoggerMap->end()) _pLoggerMap->erase(it); |
356 | } |
357 | } |
358 | |
359 | |
360 | void Logger::names(std::vector<std::string>& names) |
361 | { |
362 | Mutex::ScopedLock lock(_mapMtx); |
363 | |
364 | names.clear(); |
365 | if (_pLoggerMap) |
366 | { |
367 | for (LoggerMap::const_iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it) |
368 | { |
369 | names.push_back(it->first); |
370 | } |
371 | } |
372 | } |
373 | |
374 | |
375 | Logger& Logger::parent(const std::string& name) |
376 | { |
377 | std::string::size_type pos = name.rfind('.'); |
378 | if (pos != std::string::npos) |
379 | { |
380 | std::string pname = name.substr(0, pos); |
381 | Ptr pParent = find(pname); |
382 | if (pParent) |
383 | return *pParent; |
384 | else |
385 | return parent(pname); |
386 | } |
387 | else return unsafeGet(ROOT); |
388 | } |
389 | |
390 | |
391 | int Logger::parseLevel(const std::string& level) |
392 | { |
393 | if (icompare(level, "none" ) == 0) |
394 | return 0; |
395 | else if (icompare(level, "fatal" ) == 0) |
396 | return Message::PRIO_FATAL; |
397 | else if (icompare(level, "critical" ) == 0) |
398 | return Message::PRIO_CRITICAL; |
399 | else if (icompare(level, "error" ) == 0) |
400 | return Message::PRIO_ERROR; |
401 | else if (icompare(level, "warning" ) == 0) |
402 | return Message::PRIO_WARNING; |
403 | else if (icompare(level, "notice" ) == 0) |
404 | return Message::PRIO_NOTICE; |
405 | else if (icompare(level, "information" ) == 0) |
406 | return Message::PRIO_INFORMATION; |
407 | else if (icompare(level, "debug" ) == 0) |
408 | return Message::PRIO_DEBUG; |
409 | else if (icompare(level, "trace" ) == 0) |
410 | return Message::PRIO_TRACE; |
411 | else |
412 | { |
413 | int numLevel; |
414 | if (Poco::NumberParser::tryParse(level, numLevel)) |
415 | { |
416 | if (numLevel > 0 && numLevel < 9) |
417 | return numLevel; |
418 | else |
419 | throw InvalidArgumentException("Log level out of range " , level); |
420 | } |
421 | else |
422 | throw InvalidArgumentException("Not a valid log level" , level); |
423 | } |
424 | } |
425 | |
426 | |
427 | void Logger::add(Ptr pLogger) |
428 | { |
429 | if (!_pLoggerMap) _pLoggerMap.reset(new LoggerMap); |
430 | _pLoggerMap->insert(LoggerMap::value_type(pLogger->name(), pLogger)); |
431 | } |
432 | |
433 | |
434 | } // namespace Poco |
435 | |