Commit | Line | Data |
---|---|---|
0e23f538 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on this file might be covered by the GNU General Public License. | |
19 | */ | |
b6fb82a2 RP |
20 | /** @file |
21 | * @brief implementaton of logging functions. | |
22 | * | |
23 | * @copyright © Copyright 2007-2008 by Intra2net AG | |
57924725 TJ |
24 | * |
25 | * @note Don't call loggers from global constructed objects | |
26 | * as this depends on the global object construction sequence. | |
b6fb82a2 RP |
27 | */ |
28 | ||
29 | #include "logfunc.hpp" | |
30 | ||
31 | #include <syslog.h> | |
32 | #include <cstdlib> | |
33 | #include <ctime> | |
34 | #include <algorithm> | |
35 | #include <iostream> | |
36 | #include <fstream> | |
37 | #include <unistd.h> | |
5efd35b1 | 38 | #include <string.h> |
b6fb82a2 | 39 | #include <boost/shared_ptr.hpp> |
57924725 TJ |
40 | #include <boost/thread/recursive_mutex.hpp> |
41 | #include <boost/thread/thread.hpp> | |
b6fb82a2 RP |
42 | |
43 | #include <stringfunc.hxx> | |
44 | #include <filefunc.hxx> | |
45 | ||
46 | ||
47 | namespace I2n | |
48 | { | |
49 | namespace Logger | |
50 | { | |
51 | ||
b6fb82a2 RP |
52 | /** |
53 | * @brief the global logger instance. | |
54 | * | |
55 | * This may be used in all cases wheer a specialized logger is not available | |
56 | * or shouldn't be used for some reason. | |
57 | */ | |
58 | PartLogger GlobalLogger(""); | |
59 | ||
60 | ||
61 | namespace | |
62 | { | |
63 | ||
f4fcef65 TJ |
64 | /// Global lock for the logger. Used during all syslog operations |
65 | /// and modification of our shared local variables. | |
66 | static boost::recursive_mutex LoggerLock; | |
67 | ||
b6fb82a2 RP |
68 | /* |
69 | ** local globals: | |
70 | */ | |
71 | ||
57924725 TJ |
72 | static std::string g_ident; |
73 | static Facility g_facility; | |
74 | static bool g_syslog_opened = false; | |
75 | static int g_max_level= LogLevel::Warning; | |
b6fb82a2 | 76 | |
57924725 | 77 | static bool g_stderr_log = false; |
b6fb82a2 | 78 | |
57924725 TJ |
79 | static std::string g_log_file_name; |
80 | static boost::shared_ptr< std::ofstream > g_log_stream_ptr; | |
b6fb82a2 RP |
81 | |
82 | /** | |
83 | * @brief lookup array for translating our log levels to syslog level. | |
84 | */ | |
57924725 | 85 | static int loglevel_2_syslog_level[ LogLevel::_LogLevel_END ] = { |
f61aeac1 RP |
86 | LOG_EMERG, |
87 | LOG_ALERT, | |
88 | LOG_CRIT, | |
89 | LOG_ERR, | |
90 | LOG_WARNING, | |
91 | LOG_NOTICE, | |
92 | LOG_INFO, | |
93 | LOG_DEBUG | |
b6fb82a2 RP |
94 | }; |
95 | ||
96 | ||
97 | /** | |
98 | * @brief lookup array for translating our log levels to a short (4 character) tag. | |
99 | * | |
100 | * These tags are used when logs are written to stderr or into a log file. | |
101 | */ | |
57924725 | 102 | static std::string loglevel_2_short_tag[ LogLevel::_LogLevel_END ] = { |
f61aeac1 RP |
103 | "EMRG", |
104 | "ALRT", | |
105 | "CRIT", | |
106 | "ERR ", | |
107 | "WARN", | |
108 | "NOTE", | |
109 | "INFO", | |
110 | "DBUG" | |
b6fb82a2 RP |
111 | }; |
112 | ||
113 | ||
114 | /** | |
115 | * @brief a copy of the current identifier used for syslog. | |
116 | * | |
117 | * Keeping a copy of this ident is necessary since openlog doen't copy it's first | |
118 | * argument but copies only the pointer! (what a **censored**!) | |
119 | */ | |
57924725 | 120 | static char* syslog_ident= NULL; |
b6fb82a2 RP |
121 | |
122 | ||
123 | /* | |
124 | ** functions: | |
125 | */ | |
126 | ||
127 | /** | |
128 | * @brief close syslog. | |
129 | */ | |
130 | void close_syslog() | |
131 | { | |
57924725 TJ |
132 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
133 | ||
f61aeac1 RP |
134 | if (g_syslog_opened) |
135 | { | |
136 | closelog(); | |
137 | if (syslog_ident) | |
138 | { | |
139 | free(syslog_ident); | |
140 | syslog_ident= NULL; | |
141 | } | |
142 | g_syslog_opened= false; | |
143 | } | |
b6fb82a2 RP |
144 | } // eo close_syslog() |
145 | ||
146 | ||
147 | /** | |
148 | * @brief open syslog. | |
149 | */ | |
150 | void open_syslog() | |
151 | { | |
57924725 TJ |
152 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
153 | ||
f61aeac1 RP |
154 | close_syslog(); |
155 | syslog_ident= strdup(g_ident.c_str()); | |
156 | openlog( syslog_ident, LOG_CONS|LOG_PID, g_facility); | |
157 | g_syslog_opened= true; | |
b6fb82a2 RP |
158 | } // eo open_syslog() |
159 | ||
160 | ||
161 | /** | |
162 | * @brief get syslog level from internal log level. | |
163 | * @param level log level. | |
164 | * @return syslog level | |
165 | */ | |
166 | int get_syslog_level( int level ) | |
167 | { | |
57924725 TJ |
168 | // Note: Thread safe |
169 | ||
d0d6eef7 | 170 | if (level >=0 && level < LogLevel::_LogLevel_END) |
f61aeac1 RP |
171 | { |
172 | return loglevel_2_syslog_level[level]; | |
173 | } | |
174 | return (level<0) ? (LOG_EMERG) : (LOG_DEBUG); | |
b6fb82a2 RP |
175 | } // eo get_syslog_level(int) |
176 | ||
177 | ||
178 | /** | |
179 | * @brief get a short tag for the log level (/ message type) | |
180 | * @param level the log level | |
181 | * @return a short tag for the level. | |
182 | */ | |
183 | std::string get_level_tag( int level ) | |
184 | { | |
57924725 TJ |
185 | // Note: Thread safe |
186 | ||
d0d6eef7 | 187 | if (level >=0 && level < LogLevel::_LogLevel_END) |
f61aeac1 RP |
188 | { |
189 | return loglevel_2_short_tag[level]; | |
190 | } | |
191 | return (level<0) ? loglevel_2_short_tag[0] : loglevel_2_short_tag[ LogLevel::_LogLevel_END -1 ]; | |
b6fb82a2 RP |
192 | } // eo get_level_tag(int) |
193 | ||
194 | ||
195 | /** | |
196 | * @brief the "real" log function which logs a message at a given level. | |
197 | * @param level the log level to log the message at. | |
198 | * @param msg the message. | |
ea573ee7 | 199 | * @param keep_unsafe_chars don't replace characters that are considered unsafe to log, e.g. control characters. |
b6fb82a2 RP |
200 | * |
201 | * Write the message to every enabled log channel. | |
202 | * | |
203 | * If syslog is enabled the message is passed unmodified to syslog. | |
204 | * | |
205 | * If a stream log is enabled (stderr or file) then the message is prepended with date, time | |
206 | * and process information (like syslog does). The message is splitted at line ends and | |
207 | * consecutive lines are indented. | |
208 | */ | |
ea573ee7 | 209 | void log_msg( int level, const std::string& msg, bool keep_unsafe_chars) |
b6fb82a2 | 210 | { |
57924725 TJ |
211 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
212 | ||
f61aeac1 RP |
213 | if (not g_syslog_opened and not g_stderr_log and not g_log_stream_ptr) |
214 | { | |
215 | // if nothing is opened for logging: we activate syslog! | |
216 | enable_syslog(true); | |
217 | } | |
218 | ||
219 | if (g_syslog_opened) | |
220 | { | |
ea573ee7 GE |
221 | std::string sane_msg; |
222 | if (keep_unsafe_chars) | |
223 | sane_msg=msg; | |
224 | else | |
225 | sane_msg=sanitize_for_logging(msg); | |
226 | ||
227 | ::syslog( get_syslog_level(level), "%s", sane_msg.c_str()); | |
f61aeac1 RP |
228 | } |
229 | // file(/stream) logging: | |
230 | if (g_stderr_log or g_log_stream_ptr) // add more log "enabled" expressions here... | |
231 | { | |
232 | // here we need must do something more with the msg... | |
233 | std::string new_msg; | |
234 | std::string prefix; | |
235 | { | |
b6fb82a2 | 236 | std::ostringstream ostr; |
f61aeac1 | 237 | // add time stamp (syslog like: "Mon DD HH:MM:SS") : |
b6fb82a2 | 238 | { |
f61aeac1 RP |
239 | time_t t = time(NULL); |
240 | char buffer[32]; | |
532d6b3a TJ |
241 | struct tm ta; |
242 | if (localtime_r(&t, &ta) == NULL) | |
243 | memset(&ta, 0, sizeof(struct tm)); | |
244 | ||
245 | std::strftime(buffer, sizeof(buffer),"%b %d %H:%M:%S ", &ta); | |
f61aeac1 | 246 | ostr << buffer; |
b6fb82a2 | 247 | } |
f61aeac1 RP |
248 | ostr << get_level_tag(level) << " "; |
249 | ostr << g_ident << "[" << getpid() << "]: "; | |
250 | prefix= ostr.str(); | |
251 | } | |
252 | { | |
253 | { | |
254 | std::string indent_string(prefix.size(), ' '); | |
255 | std::list< std::string > parts; | |
256 | split_string( chomp(msg,"\n"), parts, "\n"); | |
257 | std::ostringstream ostr; | |
258 | ostr << prefix; | |
259 | for(std::list< std::string >::const_iterator it= parts.begin(); | |
260 | it != parts.end(); | |
261 | ++it) | |
262 | { | |
263 | if (it != parts.begin()) | |
264 | { | |
265 | ostr << indent_string; | |
266 | } | |
ea573ee7 GE |
267 | |
268 | if (keep_unsafe_chars) | |
269 | ostr << *it << std::endl; | |
270 | else | |
271 | ostr << sanitize_for_logging(*it) << std::endl; | |
f61aeac1 RP |
272 | } |
273 | new_msg= ostr.str(); | |
274 | } | |
275 | } | |
276 | if (g_stderr_log) | |
277 | { | |
278 | std::cerr << new_msg; | |
279 | } | |
280 | if (g_log_stream_ptr) | |
281 | { | |
282 | *g_log_stream_ptr << new_msg << std::flush; | |
283 | } | |
284 | } | |
b6fb82a2 RP |
285 | } // eo log_msg |
286 | ||
287 | ||
288 | /** | |
289 | * @brief "real" log function for part messages. | |
290 | * @param level the log level. | |
291 | * @param part the part(/module) name(/id) | |
292 | * @param msg the log message. | |
ea573ee7 | 293 | * @param keep_unsafe_chars don't replace characters that are considered unsafe to log, e.g. control characters. |
b6fb82a2 RP |
294 | * |
295 | * basically calls @a log(), but prepends the part (if not empty) in square brackets to the message. | |
296 | */ | |
297 | void log_part_msg( | |
f61aeac1 RP |
298 | int level, |
299 | const std::string& part, | |
ea573ee7 GE |
300 | const std::string& msg, |
301 | bool keep_unsafe_chars) | |
f61aeac1 | 302 | { |
57924725 TJ |
303 | // Note: Locking is done in log_msg() |
304 | ||
f61aeac1 RP |
305 | if (!part.empty()) |
306 | { | |
307 | std::ostringstream ostr; | |
308 | ostr << "[" << part << "] " << msg; | |
ea573ee7 | 309 | log_msg(level, ostr.str(), keep_unsafe_chars); |
f61aeac1 RP |
310 | } |
311 | else | |
312 | { | |
ea573ee7 | 313 | log_msg(level, msg, keep_unsafe_chars); |
f61aeac1 | 314 | } |
b6fb82a2 RP |
315 | } // eo log_part_msg(int,const std::string&,const std::string&) |
316 | ||
317 | ||
b5d5a346 RP |
318 | /** |
319 | * @brief returns the name of the program (/binary) | |
320 | * @return the program name if it could be determined; generated name else. | |
321 | * | |
322 | * Tries to determine the name of the binary. | |
323 | * | |
324 | * If no name could be determined, one is built. | |
325 | */ | |
326 | std::string get_program_name() | |
327 | { | |
57924725 TJ |
328 | // Note: Thread safe |
329 | ||
b5d5a346 RP |
330 | std::string result; |
331 | // determine the program name: | |
332 | { | |
333 | // try to determine the name using the exe link: | |
334 | std::string exe_path; | |
335 | { | |
336 | std::ostringstream ostr; | |
337 | ostr << "/proc/" << ::getpid() << "/exe"; | |
338 | exe_path= ostr.str(); | |
339 | } | |
340 | std::string binary_path= read_link(exe_path); | |
341 | if (!binary_path.empty()) | |
342 | { | |
343 | result= basename(binary_path); | |
344 | } | |
345 | } | |
346 | if (result.empty()) | |
347 | { | |
348 | // no program name found up to this point. | |
349 | // make a name (as fallback solution): | |
350 | std::ostringstream ostr; | |
351 | ostr << "prg-" << ::getpid(); | |
352 | result= ostr.str(); | |
353 | } | |
354 | return result; | |
355 | } // eo get_program_name | |
356 | ||
357 | ||
b6fb82a2 RP |
358 | |
359 | void _cleanup() | |
360 | { | |
57924725 | 361 | // Note: Locking is done in close_syslog(); |
f61aeac1 RP |
362 | close_syslog(); |
363 | //TODO other cleanups? | |
b6fb82a2 RP |
364 | } // _cleanup |
365 | ||
366 | ||
367 | class __Initializer | |
368 | { | |
f61aeac1 RP |
369 | public: |
370 | __Initializer() | |
371 | { | |
372 | std::atexit( _cleanup ); | |
373 | } | |
b6fb82a2 RP |
374 | } __initialize; |
375 | ||
376 | ||
377 | } // eo namespace <anonymous> | |
378 | ||
379 | ||
380 | ||
381 | /* | |
382 | ** implementation of Facility | |
383 | */ | |
384 | ||
385 | ||
386 | const int Facility::AuthPriv= LOG_AUTH; | |
387 | const int Facility::Cron = LOG_CRON; | |
388 | const int Facility::Daemon = LOG_DAEMON; | |
389 | const int Facility::Kern = LOG_KERN; | |
390 | const int Facility::Mail = LOG_MAIL; | |
391 | const int Facility::News = LOG_NEWS; | |
392 | const int Facility::Syslog = LOG_SYSLOG; | |
393 | const int Facility::User = LOG_USER; | |
394 | const int Facility::UUCP = LOG_UUCP; | |
395 | const int Facility::Local0 = LOG_LOCAL0; | |
396 | const int Facility::Local1 = LOG_LOCAL1; | |
397 | const int Facility::Local2 = LOG_LOCAL2; | |
398 | const int Facility::Local3 = LOG_LOCAL3; | |
399 | const int Facility::Local4 = LOG_LOCAL4; | |
400 | const int Facility::Local5 = LOG_LOCAL5; | |
401 | const int Facility::Local6 = LOG_LOCAL6; | |
402 | const int Facility::Local7 = LOG_LOCAL7; | |
403 | ||
404 | ||
405 | ||
406 | /* | |
407 | ** implementation of PartLogger::LogHelper | |
408 | */ | |
409 | ||
410 | PartLogger::LogHelper::LogHelper(PartLogger& logger, int level, const SourceLocation& loc) | |
411 | : Logger(logger) | |
412 | , Level(level) | |
413 | , Location(loc) | |
414 | { | |
f61aeac1 | 415 | StreamPtr.reset(new std::ostringstream()); |
b6fb82a2 RP |
416 | } // eo PartLogger::LogHelper::LogHelper(PartLogger&,int) |
417 | ||
418 | PartLogger::LogHelper::LogHelper(const LogHelper& helper) | |
419 | : Logger(helper.Logger) | |
420 | , Level(helper.Level) | |
421 | , Location(helper.Location) | |
422 | , StreamPtr(helper.StreamPtr) | |
423 | { | |
424 | } // eo PartLogger::LogHelper::LogHelper(const LogHelper&) | |
425 | ||
426 | ||
427 | PartLogger::LogHelper::~LogHelper() | |
428 | { | |
f61aeac1 RP |
429 | if (StreamPtr.get()) |
430 | { | |
431 | if (Location) | |
432 | { | |
433 | //*m_stream_ptr << " at " << m_loc.Line << " in " << m_loc.FunctionName; | |
434 | *StreamPtr << " @" << Location.get_location_tag(); | |
435 | } | |
436 | std::string msg(StreamPtr->str()); | |
437 | if (!msg.empty()) | |
438 | { | |
439 | Logger.log(Level,msg); | |
440 | } | |
441 | } | |
b6fb82a2 RP |
442 | } // eo PartLogger::LogHelper::~LogHelper |
443 | ||
444 | ||
445 | /* | |
446 | ** implementation of PartLogger | |
447 | */ | |
448 | ||
449 | /** | |
450 | * constructor for a part logger. | |
451 | * @param part name of the part (module name) using the logger instance. | |
452 | */ | |
453 | PartLogger::PartLogger(const std::string& part) | |
ac758a43 | 454 | : Part(part), KeepUnsafeChars(false) |
b6fb82a2 RP |
455 | { |
456 | } // eo PartLogger::PartLogger(const std.:string&) | |
457 | ||
458 | ||
459 | /** | |
460 | * @brief constructor for a part logger at module level. | |
461 | * @param loc the source location where the PartLogger is constructed. | |
462 | * | |
463 | * The part name is derived from the filename given with the source location by | |
464 | * using the basename and cutting off the C++ file suffix (if it is a well known one; | |
465 | * currently known extensions: cpp, cxx, c++, cc, C). | |
466 | */ | |
467 | PartLogger::PartLogger( const SourceLocation& loc ) | |
ac758a43 | 468 | : KeepUnsafeChars(false) |
b6fb82a2 | 469 | { |
f61aeac1 RP |
470 | if (loc.Line>0 && ! loc.File.empty()) |
471 | { | |
472 | std::string str= basename(loc.File); | |
473 | Part= remove_suffix(str,".cpp"); | |
474 | if (Part == str) Part= remove_suffix(str,".cxx"); | |
475 | if (Part == str) Part= remove_suffix(str,".c++"); | |
476 | if (Part == str) Part= remove_suffix(str,".cc"); | |
477 | if (Part == str) Part= remove_suffix(str,".C"); | |
478 | } | |
479 | else | |
480 | { | |
481 | Part="Unknown"; | |
482 | } | |
b6fb82a2 RP |
483 | }// PartLogger::PartLogger(const SourceLocation&) |
484 | ||
485 | ||
486 | PartLogger::~PartLogger() | |
487 | { | |
488 | } | |
489 | ||
490 | ||
491 | /** | |
492 | * generic log function. | |
493 | * @param level the log level. | |
494 | * @param msg the log message. | |
495 | */ | |
ea573ee7 | 496 | void PartLogger::log(int level, const std::string &msg, bool keep_unsafe_chars) |
b6fb82a2 | 497 | { |
57924725 TJ |
498 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
499 | ||
f61aeac1 RP |
500 | if (level <= g_max_level) |
501 | { | |
ea573ee7 | 502 | log_part_msg(level, Part, msg, keep_unsafe_chars); |
f61aeac1 | 503 | } |
b6fb82a2 RP |
504 | } // eo PartLogger::log(int,const std::string); |
505 | ||
506 | ||
507 | void PartLogger::fatal(const std::string& msg) | |
508 | { | |
ac758a43 | 509 | log(LOG_EMERG,msg,KeepUnsafeChars); |
b6fb82a2 RP |
510 | } // eo PartLogger::fatal(const std::string&) |
511 | ||
512 | ||
513 | void PartLogger::alert(const std::string& msg) | |
514 | { | |
ac758a43 | 515 | log(LOG_ALERT,msg,KeepUnsafeChars); |
b6fb82a2 RP |
516 | } // eo PartLogger::alert(const std::string&) |
517 | ||
518 | ||
519 | void PartLogger::critical(const std::string& msg) | |
520 | { | |
ac758a43 | 521 | log(LOG_CRIT,msg,KeepUnsafeChars); |
b6fb82a2 RP |
522 | } // eo PartLogger::critical(const std::string&) |
523 | ||
524 | ||
525 | void PartLogger::error(const std::string& msg) | |
526 | { | |
ac758a43 | 527 | log(LOG_ERR, msg,KeepUnsafeChars); |
b6fb82a2 RP |
528 | } // eo PartLogger::error(const std::string&) |
529 | ||
530 | ||
531 | void PartLogger::warning(const std::string& msg) | |
532 | { | |
ac758a43 | 533 | log(LOG_WARNING, msg,KeepUnsafeChars); |
b6fb82a2 RP |
534 | } // eo PartLogger::warning(const std::string&) |
535 | ||
536 | ||
537 | void PartLogger::notice(const std::string& msg) | |
538 | { | |
ac758a43 | 539 | log(LOG_NOTICE, msg,KeepUnsafeChars); |
b6fb82a2 RP |
540 | } // eo PartLogger::notice(const std::string&) |
541 | ||
542 | ||
543 | void PartLogger::info(const std::string& msg) | |
544 | { | |
ac758a43 | 545 | log(LOG_INFO, msg,KeepUnsafeChars); |
b6fb82a2 RP |
546 | } // eo PartLogger::info(const std::string&) |
547 | ||
548 | ||
549 | void PartLogger::debug(const std::string& msg) | |
550 | { | |
ac758a43 | 551 | log(LOG_DEBUG, msg,KeepUnsafeChars); |
b6fb82a2 RP |
552 | } // eo PartLogger::debug(const std::string&) |
553 | ||
ea573ee7 GE |
554 | void PartLogger::set_keep_unsafe_chars(bool _keep_unsafe_chars) |
555 | { | |
ac758a43 | 556 | KeepUnsafeChars=_keep_unsafe_chars; |
ea573ee7 | 557 | } |
b6fb82a2 | 558 | |
ea573ee7 GE |
559 | bool PartLogger::get_keep_unsafe_chars() |
560 | { | |
ac758a43 | 561 | return KeepUnsafeChars; |
ea573ee7 | 562 | } |
b6fb82a2 RP |
563 | |
564 | PartLogger::LogHelper PartLogger::fatal(const SourceLocation& loc) | |
565 | { | |
f61aeac1 | 566 | return PartLogger::LogHelper(*this,LOG_EMERG,loc); |
b6fb82a2 RP |
567 | } // eo PartLogger::fatal(const SourceLocation&) |
568 | ||
569 | ||
570 | PartLogger::LogHelper PartLogger::alert(const SourceLocation& loc) | |
571 | { | |
f61aeac1 | 572 | return PartLogger::LogHelper(*this,LOG_ALERT,loc); |
b6fb82a2 RP |
573 | } // eo PartLogger::alert(const SourceLocation&) |
574 | ||
575 | ||
576 | PartLogger::LogHelper PartLogger::critical(const SourceLocation& loc) | |
577 | { | |
f61aeac1 | 578 | return PartLogger::LogHelper(*this,LOG_CRIT,loc); |
b6fb82a2 RP |
579 | } // eo PartLogger::critical(const SourceLocation&) |
580 | ||
581 | ||
582 | PartLogger::LogHelper PartLogger::error(const SourceLocation& loc) | |
583 | { | |
f61aeac1 | 584 | return PartLogger::LogHelper(*this,LOG_ERR,loc); |
b6fb82a2 RP |
585 | } // eo PartLogger::error(const SourceLocation&) |
586 | ||
587 | ||
588 | PartLogger::LogHelper PartLogger::warning(const SourceLocation& loc) | |
589 | { | |
f61aeac1 | 590 | return PartLogger::LogHelper(*this,LOG_WARNING,loc); |
b6fb82a2 RP |
591 | } // eo PartLogger::warning(const SourceLocation&) |
592 | ||
593 | ||
594 | PartLogger::LogHelper PartLogger::notice(const SourceLocation& loc) | |
595 | { | |
f61aeac1 | 596 | return PartLogger::LogHelper(*this,LOG_NOTICE,loc); |
b6fb82a2 RP |
597 | } // eo PartLogger::notice(const SourceLocation&) |
598 | ||
599 | ||
600 | PartLogger::LogHelper PartLogger::info(const SourceLocation& loc) | |
601 | { | |
f61aeac1 | 602 | return PartLogger::LogHelper(*this,LOG_INFO,loc); |
b6fb82a2 RP |
603 | } // eo PartLogger::info(const SourceLocation&) |
604 | ||
605 | ||
606 | PartLogger::LogHelper PartLogger::debug(const SourceLocation& loc) | |
607 | { | |
f61aeac1 | 608 | return PartLogger::LogHelper(*this,LOG_DEBUG,loc); |
b6fb82a2 RP |
609 | } // eo PartLogger::debug(const SourceLocation&) |
610 | ||
611 | /* | |
612 | ** | |
613 | */ | |
614 | ||
615 | ||
616 | /** | |
617 | * enable logging to syslog with a name and a facility. | |
618 | * @param name the name used as ident. | |
619 | * @param facility the facility which should be used. | |
620 | */ | |
621 | void enable_syslog( const std::string& name, Facility facility ) | |
622 | { | |
57924725 TJ |
623 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
624 | ||
f61aeac1 RP |
625 | close_syslog(); |
626 | g_ident= name; | |
627 | g_facility= facility; | |
628 | open_syslog(); | |
b6fb82a2 RP |
629 | } // eo enable_syslog(const std::string,Facility) |
630 | ||
631 | ||
632 | /** | |
633 | * enable logging to syslog with a facility. | |
634 | * The ident is used from a previous call or (if none was set) is | |
635 | * determined by reading the program path from /proc/\<pid\>/exe. | |
636 | * @param facility the facility which should be used. | |
637 | */ | |
638 | void enable_syslog( Facility facility ) | |
639 | { | |
57924725 TJ |
640 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
641 | ||
f61aeac1 RP |
642 | if (g_ident.empty()) |
643 | { | |
b5d5a346 | 644 | g_ident= get_program_name(); |
f61aeac1 RP |
645 | } |
646 | close_syslog(); | |
647 | g_facility = facility; | |
648 | open_syslog(); | |
b6fb82a2 RP |
649 | } // eo enable_syslog(Facility) |
650 | ||
651 | ||
652 | /** | |
653 | * enable or disable logging to syslog. | |
654 | * @param enable whether the logging to syslog should be enabled or not. | |
655 | */ | |
656 | void enable_syslog( bool enable ) | |
657 | { | |
57924725 TJ |
658 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
659 | ||
f61aeac1 RP |
660 | if (enable) |
661 | { | |
662 | if (!g_syslog_opened) | |
663 | { | |
664 | enable_syslog( g_facility ); | |
665 | } | |
666 | } | |
667 | else // ! enable | |
668 | { | |
669 | close_syslog(); | |
670 | } | |
b6fb82a2 RP |
671 | } // eo enable_syslog(bool) |
672 | ||
673 | ||
674 | /** | |
675 | * enable/ disable loggin to stderr. | |
676 | * @param enable whether to enable or disable logging to stderr. | |
677 | */ | |
678 | void enable_stderr_log(bool enable) | |
679 | { | |
57924725 TJ |
680 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
681 | ||
f61aeac1 | 682 | g_stderr_log= enable; |
b6fb82a2 RP |
683 | } // eo enableStderr; |
684 | ||
685 | ||
686 | ||
687 | /** | |
688 | * enable logging to a file. | |
689 | * @param name path to the file. | |
690 | * | |
691 | * @note only one log file can be use at a time. | |
692 | */ | |
693 | void enable_log_file( const std::string& name ) | |
694 | { | |
57924725 TJ |
695 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
696 | ||
f61aeac1 RP |
697 | g_log_file_name= name; |
698 | g_log_stream_ptr.reset( new std::ofstream() ); | |
699 | g_log_stream_ptr->open( name.c_str(), std::ios::out|std::ios::app ); | |
700 | //std::cerr << "### opened \"" << name << "\"" << g_log_stream_ptr->good() << std::endl; | |
b6fb82a2 RP |
701 | } // eo enable_log_file(const std::string&) |
702 | ||
703 | ||
704 | /** | |
705 | * enable or disable loggin to a file. | |
b5d5a346 RP |
706 | * if a logfile was already set by a previous call to enable_log_file(const std::string&) |
707 | * that one is used; else it logs to <tt>/var/log/</tt><em>program name</em><tt>.log</tt>. | |
b6fb82a2 RP |
708 | * @param enable whether to enable or disable logging to a file. |
709 | */ | |
710 | void enable_log_file( bool enable ) | |
711 | { | |
57924725 TJ |
712 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
713 | ||
f61aeac1 RP |
714 | if (enable) |
715 | { | |
b5d5a346 RP |
716 | if (g_log_file_name.empty()) |
717 | { | |
718 | std::ostringstream ostr; | |
719 | ostr << "/var/log/" << get_program_name() << ".log"; | |
720 | enable_log_file( ostr.str() ); | |
721 | } | |
722 | else | |
f61aeac1 RP |
723 | { |
724 | enable_log_file( g_log_file_name ); | |
725 | } | |
726 | } | |
727 | else // ! enable | |
728 | { | |
729 | g_log_stream_ptr.reset(); | |
730 | } | |
b6fb82a2 RP |
731 | } // eo enable_log_file(bool) |
732 | ||
733 | ||
b5d5a346 RP |
734 | /** |
735 | * @brief returns if loging to file is enabled and active. | |
736 | * @return @a true if logfile is enabled and opened. | |
737 | */ | |
738 | bool is_logging_to_file() | |
739 | { | |
57924725 TJ |
740 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
741 | ||
b5d5a346 RP |
742 | return g_log_stream_ptr and g_log_stream_ptr->good(); |
743 | } // eo is_logging_to_file() | |
744 | ||
0ed59edf | 745 | |
0415b981 RP |
746 | |
747 | /** | |
748 | * @brief returns the current name of the log file. | |
749 | * @return the name of the log file; empty if none was given. | |
750 | * | |
751 | * This function returns the last used log file name; even | |
752 | * when logging to that file is currently disabled. | |
753 | */ | |
754 | std::string get_log_file_name() | |
755 | { | |
57924725 TJ |
756 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
757 | ||
0415b981 RP |
758 | return g_log_file_name; |
759 | } // eo get_log_file_name() | |
760 | ||
761 | ||
0ed59edf RP |
762 | /** |
763 | * @brief re-opens the logfiles (if applicable). | |
764 | */ | |
765 | void reopen() | |
766 | { | |
57924725 TJ |
767 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
768 | ||
0ed59edf RP |
769 | if (g_log_stream_ptr) |
770 | { | |
771 | enable_log_file(false); // closes log, but holds the name. | |
772 | enable_log_file(true); // opens the log file again. | |
773 | } | |
774 | } // eo reopen() | |
775 | ||
776 | ||
b6fb82a2 RP |
777 | /** |
778 | * set a new log level. | |
779 | * @param level the new log level. | |
780 | * @return the previous log level. | |
781 | */ | |
782 | int set_log_level(int level) | |
783 | { | |
57924725 TJ |
784 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
785 | ||
a47d646e TJ |
786 | int previous = g_max_level; |
787 | ||
788 | // Sanity check | |
789 | if (level < LogLevel::Emergency) | |
790 | level = LogLevel::Emergency; | |
791 | else if (level > LogLevel::Debug) | |
792 | level = LogLevel::Debug; | |
793 | ||
794 | g_max_level = level; | |
795 | ||
796 | return previous; | |
b6fb82a2 RP |
797 | } // eo set_log_level(int) |
798 | ||
799 | ||
800 | /** | |
801 | * returns the current log level. | |
802 | * @return the current log level. | |
803 | */ | |
804 | int get_log_level() | |
805 | { | |
57924725 TJ |
806 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
807 | ||
f61aeac1 | 808 | return g_max_level; |
b6fb82a2 RP |
809 | } // eo get_log_level() |
810 | ||
811 | ||
812 | /** | |
813 | * returns if the current log level covers the given level. | |
814 | * This is a convenience function for optimization of log output (especially debug output). | |
815 | * @param level the level which should be tested for. | |
816 | * @return @a true iff a message with the level would be written out. | |
817 | */ | |
818 | bool has_log_level(int level) | |
819 | { | |
57924725 TJ |
820 | boost::recursive_mutex::scoped_lock lock(LoggerLock); |
821 | ||
f61aeac1 | 822 | return (g_max_level >= level); |
b6fb82a2 RP |
823 | } // eo has_log_level(int) |
824 | ||
825 | ||
826 | ||
89a410b0 CH |
827 | /** |
828 | * returns a string representation of the current log level. | |
829 | * @return a string corresponding to get_log_level | |
830 | */ | |
831 | std::string get_log_level_string() | |
832 | { | |
833 | int level = get_log_level(); | |
834 | ||
835 | if (level < 0) | |
836 | return "Emergency"; | |
837 | else if (level >= LogLevel::_LogLevel_END) | |
838 | return "Debug"; | |
839 | else | |
840 | { | |
841 | switch (level) | |
842 | { | |
843 | case LogLevel::Debug: return "Debug"; break; | |
844 | case LogLevel::Info: return "Info"; break; | |
845 | case LogLevel::Notice: return "Notice"; break; | |
846 | case LogLevel::Warning: return "Warning"; break; | |
847 | case LogLevel::Error: return "Error"; break; | |
848 | case LogLevel::Critical: return "Critical"; break; | |
849 | case LogLevel::Alert: return "Alert"; break; | |
850 | case LogLevel::Emergency: return "Emergency"; break; | |
851 | default: return "Non-standard"; break; | |
852 | } | |
853 | } | |
854 | } // eo get_log_level_string | |
855 | ||
856 | ||
b6fb82a2 RP |
857 | } // eo namespace Logger |
858 | } // eo namespace I2n |