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
24namespace Poco {
25
26
27Logger::Logger(const std::string& name, Channel::Ptr pChannel, int level): _name(name), _pChannel(pChannel), _level(level)
28{
29}
30
31
32Logger::~Logger()
33{
34}
35
36
37void Logger::setChannel(Channel::Ptr pChannel)
38{
39 _pChannel = pChannel;
40}
41
42
43Channel::Ptr Logger::getChannel() const
44{
45 return _pChannel;
46}
47
48
49void Logger::setLevel(int level)
50{
51 _level = level;
52}
53
54
55void Logger::setLevel(const std::string& level)
56{
57 setLevel(parseLevel(level));
58}
59
60
61void 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
72void Logger::log(const Message& msg)
73{
74 if (_level >= msg.getPriority() && _pChannel)
75 {
76 _pChannel->log(msg);
77 }
78}
79
80
81void Logger::log(const Exception& exc)
82{
83 error(exc.displayText());
84}
85
86
87void Logger::log(const Exception& exc, const char* file, int line)
88{
89 error(exc.displayText(), file, line);
90}
91
92
93void 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
104void 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
123void 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
142void 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
161std::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
171std::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
182std::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
194std::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
207std::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
239void Logger::formatDump(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
274Logger& Logger::get(const std::string& name)
275{
276 Mutex::ScopedLock lock(_mapMtx);
277
278 return unsafeGet(name);
279}
280
281
282Logger& 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
302Logger& 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
313Logger& Logger::root()
314{
315 Mutex::ScopedLock lock(_mapMtx);
316
317 return unsafeGet(ROOT);
318}
319
320
321Logger::Ptr Logger::has(const std::string& name)
322{
323 Mutex::ScopedLock lock(_mapMtx);
324
325 return find(name);
326}
327
328
329void Logger::shutdown()
330{
331 Mutex::ScopedLock lock(_mapMtx);
332
333 _pLoggerMap.reset();
334}
335
336
337Logger::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
348void 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
360void 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
375Logger& 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
391int 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
427void 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