* @brief implementaton of logging functions.
*
* @copyright © Copyright 2007-2008 by Intra2net AG
- *
- * @note This module is not thread safe!
- * @todo make this module thread safe (only useful when we can use threads...)
+ *
+ * @note Don't call loggers from global constructed objects
+ * as this depends on the global object construction sequence.
*/
#include "logfunc.hpp"
#include <unistd.h>
#include <string.h>
#include <boost/shared_ptr.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
#include <stringfunc.hxx>
#include <filefunc.hxx>
namespace Logger
{
+/// Global lock for the logger. Used during all syslog operations
+/// and modification of our shared local variables.
+boost::recursive_mutex LoggerLock;
/**
* @brief the global logger instance.
** local globals:
*/
-std::string g_ident;
-Facility g_facility;
-bool g_syslog_opened = false;
-int g_max_level= LogLevel::Warning;
-
-bool g_stderr_log = false;
+static std::string g_ident;
+static Facility g_facility;
+static bool g_syslog_opened = false;
+static int g_max_level= LogLevel::Warning;
-std::string g_log_file_name;
-boost::shared_ptr< std::ofstream > g_log_stream_ptr;
+static bool g_stderr_log = false;
+static std::string g_log_file_name;
+static boost::shared_ptr< std::ofstream > g_log_stream_ptr;
/**
* @brief lookup array for translating our log levels to syslog level.
*/
-int loglevel_2_syslog_level[ LogLevel::_LogLevel_END ] = {
+static int loglevel_2_syslog_level[ LogLevel::_LogLevel_END ] = {
LOG_EMERG,
LOG_ALERT,
LOG_CRIT,
*
* These tags are used when logs are written to stderr or into a log file.
*/
-std::string loglevel_2_short_tag[ LogLevel::_LogLevel_END ] = {
+static std::string loglevel_2_short_tag[ LogLevel::_LogLevel_END ] = {
"EMRG",
"ALRT",
"CRIT",
* Keeping a copy of this ident is necessary since openlog doen't copy it's first
* argument but copies only the pointer! (what a **censored**!)
*/
-char* syslog_ident= NULL;
+static char* syslog_ident= NULL;
/*
*/
void close_syslog()
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
if (g_syslog_opened)
{
closelog();
*/
void open_syslog()
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
close_syslog();
syslog_ident= strdup(g_ident.c_str());
openlog( syslog_ident, LOG_CONS|LOG_PID, g_facility);
*/
int get_syslog_level( int level )
{
+ // Note: Thread safe
+
if (level >=0 && level < LogLevel::_LogLevel_END)
{
return loglevel_2_syslog_level[level];
*/
std::string get_level_tag( int level )
{
+ // Note: Thread safe
+
if (level >=0 && level < LogLevel::_LogLevel_END)
{
return loglevel_2_short_tag[level];
*/
void log_msg( int level, const std::string& msg)
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
if (not g_syslog_opened and not g_stderr_log and not g_log_stream_ptr)
{
// if nothing is opened for logging: we activate syslog!
const std::string& part,
const std::string& msg)
{
+ // Note: Locking is done in log_msg()
+
if (!part.empty())
{
std::ostringstream ostr;
*/
std::string get_program_name()
{
+ // Note: Thread safe
+
std::string result;
// determine the program name:
{
void _cleanup()
{
+ // Note: Locking is done in close_syslog();
close_syslog();
//TODO other cleanups?
} // _cleanup
*/
void PartLogger::log(int level, const std::string msg)
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
if (level <= g_max_level)
{
log_part_msg(level, Part, msg);
*/
void enable_syslog( const std::string& name, Facility facility )
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
close_syslog();
g_ident= name;
g_facility= facility;
*/
void enable_syslog( Facility facility )
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
if (g_ident.empty())
{
g_ident= get_program_name();
*/
void enable_syslog( bool enable )
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
if (enable)
{
if (!g_syslog_opened)
*/
void enable_stderr_log(bool enable)
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
g_stderr_log= enable;
} // eo enableStderr;
*/
void enable_log_file( const std::string& name )
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
g_log_file_name= name;
g_log_stream_ptr.reset( new std::ofstream() );
g_log_stream_ptr->open( name.c_str(), std::ios::out|std::ios::app );
*/
void enable_log_file( bool enable )
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
if (enable)
{
if (g_log_file_name.empty())
*/
bool is_logging_to_file()
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
return g_log_stream_ptr and g_log_stream_ptr->good();
} // eo is_logging_to_file()
*/
std::string get_log_file_name()
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
return g_log_file_name;
} // eo get_log_file_name()
*/
void reopen()
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
if (g_log_stream_ptr)
{
enable_log_file(false); // closes log, but holds the name.
*/
int set_log_level(int level)
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
int previous = g_max_level;
// Sanity check
*/
int get_log_level()
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
return g_max_level;
} // eo get_log_level()
*/
bool has_log_level(int level)
{
+ boost::recursive_mutex::scoped_lock lock(LoggerLock);
+
return (g_max_level >= level);
} // eo has_log_level(int)