Increase version to 2.9
[libi2ncommon] / src / logfunc.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on 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
47namespace I2n
48{
49namespace 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 */
58PartLogger GlobalLogger("");
59
60
61namespace
62{
63
f4fcef65
TJ
64/// Global lock for the logger. Used during all syslog operations
65/// and modification of our shared local variables.
66static boost::recursive_mutex LoggerLock;
67
b6fb82a2
RP
68/*
69** local globals:
70*/
71
57924725
TJ
72static std::string g_ident;
73static Facility g_facility;
74static bool g_syslog_opened = false;
75static int g_max_level= LogLevel::Warning;
b6fb82a2 76
57924725 77static bool g_stderr_log = false;
b6fb82a2 78
57924725
TJ
79static std::string g_log_file_name;
80static 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 85static 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 102static 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 120static char* syslog_ident= NULL;
b6fb82a2
RP
121
122
123/*
124** functions:
125*/
126
127/**
128 * @brief close syslog.
129 */
130void 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 */
150void 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 */
166int 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 */
183std::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 209void 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 */
297void 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 */
326std::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
359void _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
367class __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
386const int Facility::AuthPriv= LOG_AUTH;
387const int Facility::Cron = LOG_CRON;
388const int Facility::Daemon = LOG_DAEMON;
389const int Facility::Kern = LOG_KERN;
390const int Facility::Mail = LOG_MAIL;
391const int Facility::News = LOG_NEWS;
392const int Facility::Syslog = LOG_SYSLOG;
393const int Facility::User = LOG_USER;
394const int Facility::UUCP = LOG_UUCP;
395const int Facility::Local0 = LOG_LOCAL0;
396const int Facility::Local1 = LOG_LOCAL1;
397const int Facility::Local2 = LOG_LOCAL2;
398const int Facility::Local3 = LOG_LOCAL3;
399const int Facility::Local4 = LOG_LOCAL4;
400const int Facility::Local5 = LOG_LOCAL5;
401const int Facility::Local6 = LOG_LOCAL6;
402const int Facility::Local7 = LOG_LOCAL7;
403
404
405
406/*
407** implementation of PartLogger::LogHelper
408*/
409
410PartLogger::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
418PartLogger::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
427PartLogger::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 */
453PartLogger::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 */
467PartLogger::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
486PartLogger::~PartLogger()
487{
488}
489
490
491/**
492 * generic log function.
493 * @param level the log level.
494 * @param msg the log message.
495 */
ea573ee7 496void 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
507void 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
513void 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
519void 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
525void 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
531void 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
537void 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
543void 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
549void 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
554void PartLogger::set_keep_unsafe_chars(bool _keep_unsafe_chars)
555{
ac758a43 556 KeepUnsafeChars=_keep_unsafe_chars;
ea573ee7 557}
b6fb82a2 558
ea573ee7
GE
559bool PartLogger::get_keep_unsafe_chars()
560{
ac758a43 561 return KeepUnsafeChars;
ea573ee7 562}
b6fb82a2
RP
563
564PartLogger::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
570PartLogger::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
576PartLogger::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
582PartLogger::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
588PartLogger::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
594PartLogger::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
600PartLogger::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
606PartLogger::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 */
621void 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 */
638void 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 */
656void 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 */
678void 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 */
693void 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 */
710void 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 */
738bool 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 */
754std::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 */
765void 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 */
782int 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 */
804int 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 */
818bool 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 */
831std::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