# the library search path.
lib_LTLIBRARIES = libi2ncommon.la
include_HEADERS = containerfunc.hpp daemonfunc.hpp filefunc.hxx \
- insocketstream.hxx ip_type.hxx ipfunc.hxx logread.hxx oftmpstream.hxx pidfile.hpp \
- pipestream.hxx stringfunc.hxx timefunc.hxx userfunc.hpp
+ insocketstream.hxx ip_type.hxx ipfunc.hxx log_macros.hpp logfunc.hpp logread.hxx \
+ oftmpstream.hxx pidfile.hpp pipestream.hxx source_track_basics.hpp stringfunc.hxx \
+ timefunc.hxx tracefunc.hpp userfunc.hpp
libi2ncommon_la_SOURCES = containerfunc.cpp daemonfunc.cpp filefunc.cpp \
- ipfunc.cpp logread.cpp oftmpstream.cpp pidfile.cpp stringfunc.cpp timefunc.cpp \
- userfunc.cpp
+ ipfunc.cpp logfunc.cpp logread.cpp oftmpstream.cpp pidfile.cpp \
+ source_track_basics.cpp stringfunc.cpp timefunc.cpp tracefunc.cpp userfunc.cpp
# Note: If you specify a:b:c as the version in the next line,
# the library that is made has version (a-c).c.b. In this
--- /dev/null
+/** @file
+ * @brief macros to ease some common logging cases.
+ *
+ * The log macros are put into a file separate from the (base) logging files since
+ * every coder can decide if he/she want's to use these macros or not.
+ * (Not everyone like macros...)
+ *
+ *
+ * @author Reinhard Pfau \<reinhard.pfau@intra2net.com\>
+ *
+ * @copyright © Copyright 2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ *
+ */
+
+#ifndef __I2N_COMMON_LOG_MACROS_HPP__
+#define __I2N_COMMON_LOG_MACROS_HPP__
+
+#include "logfunc.hpp"
+
+
+/*
+**
+*/
+
+/**
+ * @brief to be inserted in prepared but unimplemented functions.
+ */
+#define UNIMPLEMENTED() do{ ::I2n::Logger::GlobalLogger.warning(HERE) << "not implemented"; }while(false)
+
+
+/**
+ * @brief to be inserted in places which should be never reached during normal program execution.
+ */
+#define NOT_REACHED() do{ ::I2n::Logger::GlobalLogger.alert(HERE) << "this part should not be reached"; }while(false)
+
+
+
+
+#endif
--- /dev/null
+/** @file
+ * @brief implementaton of logging functions.
+ *
+ * @copyright © Copyright 2007-2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ *
+ * @note This module is not thread safe!
+ * @todo make this module thread safe (only useful when we can use threads...)
+ */
+
+#include "logfunc.hpp"
+
+#include <syslog.h>
+#include <cstdlib>
+#include <ctime>
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <boost/shared_ptr.hpp>
+
+#include <stringfunc.hxx>
+#include <filefunc.hxx>
+
+
+namespace I2n
+{
+namespace Logger
+{
+
+
+/**
+ * @brief the global logger instance.
+ *
+ * This may be used in all cases wheer a specialized logger is not available
+ * or shouldn't be used for some reason.
+ */
+PartLogger GlobalLogger("");
+
+
+namespace
+{
+
+/*
+** 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;
+
+std::string g_log_file_name;
+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 ] = {
+ LOG_EMERG,
+ LOG_ALERT,
+ LOG_CRIT,
+ LOG_ERR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_INFO,
+ LOG_DEBUG
+};
+
+
+/**
+ * @brief lookup array for translating our log levels to a short (4 character) tag.
+ *
+ * These tags are used when logs are written to stderr or into a log file.
+ */
+std::string loglevel_2_short_tag[ LogLevel::_LogLevel_END ] = {
+ "EMRG",
+ "ALRT",
+ "CRIT",
+ "ERR ",
+ "WARN",
+ "NOTE",
+ "INFO",
+ "DBUG"
+};
+
+
+/**
+ * @brief a copy of the current identifier used for syslog.
+ *
+ * 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;
+
+
+/*
+** functions:
+*/
+
+/**
+ * @brief close syslog.
+ */
+void close_syslog()
+{
+ if (g_syslog_opened)
+ {
+ closelog();
+ if (syslog_ident)
+ {
+ free(syslog_ident);
+ syslog_ident= NULL;
+ }
+ g_syslog_opened= false;
+ }
+} // eo close_syslog()
+
+
+/**
+ * @brief open syslog.
+ */
+void open_syslog()
+{
+ close_syslog();
+ syslog_ident= strdup(g_ident.c_str());
+ openlog( syslog_ident, LOG_CONS|LOG_PID, g_facility);
+ g_syslog_opened= true;
+} // eo open_syslog()
+
+
+/**
+ * @brief get syslog level from internal log level.
+ * @param level log level.
+ * @return syslog level
+ */
+int get_syslog_level( int level )
+{
+ if (level >=0 && level <= LogLevel::_LogLevel_END)
+ {
+ return loglevel_2_syslog_level[level];
+ }
+ return (level<0) ? (LOG_EMERG) : (LOG_DEBUG);
+} // eo get_syslog_level(int)
+
+
+/**
+ * @brief get a short tag for the log level (/ message type)
+ * @param level the log level
+ * @return a short tag for the level.
+ */
+std::string get_level_tag( int level )
+{
+ if (level >=0 && level <= LogLevel::_LogLevel_END)
+ {
+ return loglevel_2_short_tag[level];
+ }
+ return (level<0) ? loglevel_2_short_tag[0] : loglevel_2_short_tag[ LogLevel::_LogLevel_END -1 ];
+} // eo get_level_tag(int)
+
+
+/**
+ * @brief the "real" log function which logs a message at a given level.
+ * @param level the log level to log the message at.
+ * @param msg the message.
+ *
+ * Write the message to every enabled log channel.
+ *
+ * If syslog is enabled the message is passed unmodified to syslog.
+ *
+ * If a stream log is enabled (stderr or file) then the message is prepended with date, time
+ * and process information (like syslog does). The message is splitted at line ends and
+ * consecutive lines are indented.
+ */
+void log_msg( int level, const std::string& msg)
+{
+ 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!
+ enable_syslog(true);
+ }
+
+ if (g_syslog_opened)
+ {
+ ::syslog( get_syslog_level(level), "%s", msg.c_str());
+ }
+ // file(/stream) logging:
+ if (g_stderr_log or g_log_stream_ptr) // add more log "enabled" expressions here...
+ {
+ // here we need must do something more with the msg...
+ std::string new_msg;
+ std::string prefix;
+ {
+ std::ostringstream ostr;
+ // add time stamp (syslog like: "Mon DD HH:MM:SS") :
+ {
+ time_t t = time(NULL);
+ char buffer[32];
+ std::strftime(buffer, sizeof(buffer),"%b %d %H:%M:%S ", std::localtime(&t));
+ ostr << buffer;
+ }
+ ostr << get_level_tag(level) << " ";
+ ostr << g_ident << "[" << getpid() << "]: ";
+ prefix= ostr.str();
+ }
+ {
+ {
+ std::string indent_string(prefix.size(), ' ');
+ std::list< std::string > parts;
+ split_string( chomp(msg,"\n"), parts, "\n");
+ std::ostringstream ostr;
+ ostr << prefix;
+ for(std::list< std::string >::const_iterator it= parts.begin();
+ it != parts.end();
+ ++it)
+ {
+ if (it != parts.begin())
+ {
+ ostr << indent_string;
+ }
+ ostr << *it << std::endl;
+ }
+ new_msg= ostr.str();
+ }
+ }
+ if (g_stderr_log)
+ {
+ std::cerr << new_msg;
+ }
+ if (g_log_stream_ptr)
+ {
+ *g_log_stream_ptr << new_msg << std::flush;
+ }
+ }
+} // eo log_msg
+
+
+/**
+ * @brief "real" log function for part messages.
+ * @param level the log level.
+ * @param part the part(/module) name(/id)
+ * @param msg the log message.
+ *
+ * basically calls @a log(), but prepends the part (if not empty) in square brackets to the message.
+ */
+void log_part_msg(
+ int level,
+ const std::string& part,
+ const std::string& msg)
+{
+ if (!part.empty())
+ {
+ std::ostringstream ostr;
+ ostr << "[" << part << "] " << msg;
+ log_msg(level, ostr.str());
+ }
+ else
+ {
+ log_msg(level, msg);
+ }
+} // eo log_part_msg(int,const std::string&,const std::string&)
+
+
+
+void _cleanup()
+{
+ close_syslog();
+ //TODO other cleanups?
+} // _cleanup
+
+
+class __Initializer
+{
+ public:
+ __Initializer()
+ {
+ std::atexit( _cleanup );
+ }
+} __initialize;
+
+
+} // eo namespace <anonymous>
+
+
+
+/*
+** implementation of Facility
+*/
+
+
+const int Facility::AuthPriv= LOG_AUTH;
+const int Facility::Cron = LOG_CRON;
+const int Facility::Daemon = LOG_DAEMON;
+const int Facility::Kern = LOG_KERN;
+const int Facility::Mail = LOG_MAIL;
+const int Facility::News = LOG_NEWS;
+const int Facility::Syslog = LOG_SYSLOG;
+const int Facility::User = LOG_USER;
+const int Facility::UUCP = LOG_UUCP;
+const int Facility::Local0 = LOG_LOCAL0;
+const int Facility::Local1 = LOG_LOCAL1;
+const int Facility::Local2 = LOG_LOCAL2;
+const int Facility::Local3 = LOG_LOCAL3;
+const int Facility::Local4 = LOG_LOCAL4;
+const int Facility::Local5 = LOG_LOCAL5;
+const int Facility::Local6 = LOG_LOCAL6;
+const int Facility::Local7 = LOG_LOCAL7;
+
+
+
+/*
+** implementation of PartLogger::LogHelper
+*/
+
+PartLogger::LogHelper::LogHelper(PartLogger& logger, int level, const SourceLocation& loc)
+: Logger(logger)
+, Level(level)
+, Location(loc)
+{
+ StreamPtr.reset(new std::ostringstream());
+} // eo PartLogger::LogHelper::LogHelper(PartLogger&,int)
+
+PartLogger::LogHelper::LogHelper(const LogHelper& helper)
+: Logger(helper.Logger)
+, Level(helper.Level)
+, Location(helper.Location)
+, StreamPtr(helper.StreamPtr)
+{
+} // eo PartLogger::LogHelper::LogHelper(const LogHelper&)
+
+
+PartLogger::LogHelper::~LogHelper()
+{
+ if (StreamPtr.get())
+ {
+ if (Location)
+ {
+ //*m_stream_ptr << " at " << m_loc.Line << " in " << m_loc.FunctionName;
+ *StreamPtr << " @" << Location.get_location_tag();
+ }
+ std::string msg(StreamPtr->str());
+ if (!msg.empty())
+ {
+ Logger.log(Level,msg);
+ }
+ }
+} // eo PartLogger::LogHelper::~LogHelper
+
+
+/*
+** implementation of PartLogger
+*/
+
+/**
+ * constructor for a part logger.
+ * @param part name of the part (module name) using the logger instance.
+ */
+PartLogger::PartLogger(const std::string& part)
+: Part(part)
+{
+} // eo PartLogger::PartLogger(const std.:string&)
+
+
+/**
+ * @brief constructor for a part logger at module level.
+ * @param loc the source location where the PartLogger is constructed.
+ *
+ * The part name is derived from the filename given with the source location by
+ * using the basename and cutting off the C++ file suffix (if it is a well known one;
+ * currently known extensions: cpp, cxx, c++, cc, C).
+ */
+PartLogger::PartLogger( const SourceLocation& loc )
+{
+ if (loc.Line>0 && ! loc.File.empty())
+ {
+ std::string str= basename(loc.File);
+ Part= remove_suffix(str,".cpp");
+ if (Part == str) Part= remove_suffix(str,".cxx");
+ if (Part == str) Part= remove_suffix(str,".c++");
+ if (Part == str) Part= remove_suffix(str,".cc");
+ if (Part == str) Part= remove_suffix(str,".C");
+ }
+ else
+ {
+ Part="Unknown";
+ }
+}// PartLogger::PartLogger(const SourceLocation&)
+
+
+PartLogger::~PartLogger()
+{
+}
+
+
+/**
+ * generic log function.
+ * @param level the log level.
+ * @param msg the log message.
+ */
+void PartLogger::log(int level, const std::string msg)
+{
+ if (level <= g_max_level)
+ {
+ log_part_msg(level, Part, msg);
+ }
+} // eo PartLogger::log(int,const std::string);
+
+
+void PartLogger::fatal(const std::string& msg)
+{
+ log(LOG_EMERG,msg);
+} // eo PartLogger::fatal(const std::string&)
+
+
+void PartLogger::alert(const std::string& msg)
+{
+ log(LOG_ALERT,msg);
+} // eo PartLogger::alert(const std::string&)
+
+
+void PartLogger::critical(const std::string& msg)
+{
+ log(LOG_CRIT,msg);
+} // eo PartLogger::critical(const std::string&)
+
+
+void PartLogger::error(const std::string& msg)
+{
+ log(LOG_ERR, msg);
+} // eo PartLogger::error(const std::string&)
+
+
+void PartLogger::warning(const std::string& msg)
+{
+ log(LOG_WARNING, msg);
+} // eo PartLogger::warning(const std::string&)
+
+
+void PartLogger::notice(const std::string& msg)
+{
+ log(LOG_NOTICE, msg);
+} // eo PartLogger::notice(const std::string&)
+
+
+void PartLogger::info(const std::string& msg)
+{
+ log(LOG_INFO, msg);
+} // eo PartLogger::info(const std::string&)
+
+
+void PartLogger::debug(const std::string& msg)
+{
+ log(LOG_DEBUG, msg);
+} // eo PartLogger::debug(const std::string&)
+
+
+
+PartLogger::LogHelper PartLogger::fatal(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_EMERG,loc);
+} // eo PartLogger::fatal(const SourceLocation&)
+
+
+PartLogger::LogHelper PartLogger::alert(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_ALERT,loc);
+} // eo PartLogger::alert(const SourceLocation&)
+
+
+PartLogger::LogHelper PartLogger::critical(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_CRIT,loc);
+} // eo PartLogger::critical(const SourceLocation&)
+
+
+PartLogger::LogHelper PartLogger::error(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_ERR,loc);
+} // eo PartLogger::error(const SourceLocation&)
+
+
+PartLogger::LogHelper PartLogger::warning(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_WARNING,loc);
+} // eo PartLogger::warning(const SourceLocation&)
+
+
+PartLogger::LogHelper PartLogger::notice(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_NOTICE,loc);
+} // eo PartLogger::notice(const SourceLocation&)
+
+
+PartLogger::LogHelper PartLogger::info(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_INFO,loc);
+} // eo PartLogger::info(const SourceLocation&)
+
+
+PartLogger::LogHelper PartLogger::debug(const SourceLocation& loc)
+{
+ return PartLogger::LogHelper(*this,LOG_DEBUG,loc);
+} // eo PartLogger::debug(const SourceLocation&)
+
+/*
+**
+*/
+
+
+/**
+ * enable logging to syslog with a name and a facility.
+ * @param name the name used as ident.
+ * @param facility the facility which should be used.
+ */
+void enable_syslog( const std::string& name, Facility facility )
+{
+ close_syslog();
+ g_ident= name;
+ g_facility= facility;
+ open_syslog();
+} // eo enable_syslog(const std::string,Facility)
+
+
+/**
+ * enable logging to syslog with a facility.
+ * The ident is used from a previous call or (if none was set) is
+ * determined by reading the program path from /proc/\<pid\>/exe.
+ * @param facility the facility which should be used.
+ */
+void enable_syslog( Facility facility )
+{
+ if (g_ident.empty())
+ {
+ // determine the program name:
+ std::string exe_path;
+ {
+ std::ostringstream ostr;
+ ostr << "/proc/" << ::getpid() << "/exe";
+ exe_path= ostr.str();
+ }
+ std::string binary_path= read_link(exe_path);
+ if (!binary_path.empty())
+ {
+ g_ident= basename(binary_path);
+ }
+ }
+ close_syslog();
+ g_facility = facility;
+ open_syslog();
+} // eo enable_syslog(Facility)
+
+
+/**
+ * enable or disable logging to syslog.
+ * @param enable whether the logging to syslog should be enabled or not.
+ */
+void enable_syslog( bool enable )
+{
+ if (enable)
+ {
+ if (!g_syslog_opened)
+ {
+ enable_syslog( g_facility );
+ }
+ }
+ else // ! enable
+ {
+ close_syslog();
+ }
+} // eo enable_syslog(bool)
+
+
+/**
+ * enable/ disable loggin to stderr.
+ * @param enable whether to enable or disable logging to stderr.
+ */
+void enable_stderr_log(bool enable)
+{
+ g_stderr_log= enable;
+} // eo enableStderr;
+
+
+
+/**
+ * enable logging to a file.
+ * @param name path to the file.
+ *
+ * @note only one log file can be use at a time.
+ */
+void enable_log_file( const std::string& name )
+{
+ 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 );
+ //std::cerr << "### opened \"" << name << "\"" << g_log_stream_ptr->good() << std::endl;
+} // eo enable_log_file(const std::string&)
+
+
+/**
+ * enable or disable loggin to a file.
+ * enabling required a filename to be set by a previous call to
+ * enable_log_file(const std::string&).
+ * @param enable whether to enable or disable logging to a file.
+ */
+void enable_log_file( bool enable )
+{
+ if (enable)
+ {
+ if (! g_log_file_name.empty())
+ {
+ enable_log_file( g_log_file_name );
+ }
+ }
+ else // ! enable
+ {
+ g_log_stream_ptr.reset();
+ }
+} // eo enable_log_file(bool)
+
+
+/**
+ * set a new log level.
+ * @param level the new log level.
+ * @return the previous log level.
+ */
+int set_log_level(int level)
+{
+ int result = g_max_level;
+ g_max_level = std::max( LOG_CRIT, level );
+ return result;
+} // eo set_log_level(int)
+
+
+/**
+ * returns the current log level.
+ * @return the current log level.
+ */
+int get_log_level()
+{
+ return g_max_level;
+} // eo get_log_level()
+
+
+/**
+ * returns if the current log level covers the given level.
+ * This is a convenience function for optimization of log output (especially debug output).
+ * @param level the level which should be tested for.
+ * @return @a true iff a message with the level would be written out.
+ */
+bool has_log_level(int level)
+{
+ return (g_max_level >= level);
+} // eo has_log_level(int)
+
+
+
+} // eo namespace Logger
+} // eo namespace I2n
--- /dev/null
+/** @file
+ * @brief provides logging functions.
+ *
+ * @copyright © Copyright 2007-2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ */
+
+#ifndef __I2N_COMMON_LOGFUNC_HPP__
+#define __I2N_COMMON_LOGFUNC_HPP__
+
+
+#include <string>
+#include <ostream>
+#include <sstream>
+#include <memory>
+#include <exception>
+#include <stdexcept>
+
+#include <boost/shared_ptr.hpp>
+
+#include "source_track_basics.hpp"
+
+
+
+/*
+**
+*/
+
+namespace I2n
+{
+namespace Logger
+{
+
+
+
+/**
+ * wrapper class for syslog facility constants:
+ *
+ * @note we don't use an enum here since we import the values from
+ * the appropriate system header files internally.
+ */
+struct Facility
+{
+
+ static const int AuthPriv;
+ static const int Cron;
+ static const int Daemon;
+ static const int Kern;
+ static const int Mail;
+ static const int News;
+ static const int Syslog;
+ static const int User;
+ static const int UUCP;
+ static const int Local0;
+ static const int Local1;
+ static const int Local2;
+ static const int Local3;
+ static const int Local4;
+ static const int Local5;
+ static const int Local6;
+ static const int Local7;
+
+ int m_facility;
+
+ Facility(int facility = Facility::User) : m_facility(facility) {}
+
+ operator int() const { return m_facility; }
+}; // eo Facility
+
+
+/**
+ * struct for log level constants.
+ */
+struct LogLevel
+{
+ enum {
+ Emergency = 0, Fatal= Emergency,
+ Alert,
+ Critical,
+ Error,
+ Warning,
+ Notice,
+ Info,
+ Debug,
+ _LogLevel_END
+ };
+
+ int m_level;
+
+ LogLevel(int level= Warning) : m_level(level) {}
+
+ operator int() const { return m_level; }
+}; // eo struct LogLevel
+
+
+/**
+ * part logger.
+ * Provides a logging object to be used within a module (part).
+ */
+class PartLogger
+{
+ public:
+
+ class LogHelper
+ {
+ public:
+ virtual ~LogHelper();
+
+ template< typename T >
+ std::ostream& operator << (T v)
+ {
+ if (StreamPtr.get())
+ {
+ return *StreamPtr << v;
+ }
+ throw std::logic_error("pointer vanished");
+ } // eo operator <<(T)
+
+ protected:
+ friend class PartLogger;
+
+ LogHelper(PartLogger& logger, int level, const SourceLocation& loc);
+ LogHelper(const LogHelper& helper);
+
+ protected:
+
+ PartLogger& Logger;
+ int Level;
+ SourceLocation Location;
+ mutable std::auto_ptr< std::ostringstream > StreamPtr;
+ }; // eo class LogHelper
+
+
+ public:
+ PartLogger( const std::string& part );
+ PartLogger( const SourceLocation& loc );
+ virtual ~PartLogger();
+
+ void log(int level, const std::string msg);
+
+ void fatal(const std::string& msg);
+ void alert(const std::string& msg);
+ void critical(const std::string& msg);
+ void error(const std::string& msg);
+ void warning(const std::string& msg);
+ void notice(const std::string& msg);
+ void info(const std::string& msg);
+ void debug(const std::string& msg);
+
+ LogHelper fatal(const SourceLocation& loc= SourceLocation());
+ LogHelper alert(const SourceLocation& loc= SourceLocation());
+ LogHelper critical(const SourceLocation& loc= SourceLocation());
+ LogHelper error(const SourceLocation& loc= SourceLocation());
+ LogHelper warning(const SourceLocation& loc= SourceLocation());
+ LogHelper notice(const SourceLocation& loc= SourceLocation());
+ LogHelper info(const SourceLocation& loc= SourceLocation());
+ LogHelper debug(const SourceLocation& loc= SourceLocation());
+
+ protected:
+
+ std::string Part;
+
+}; // eo class PartLogger
+
+typedef boost::shared_ptr< PartLogger > PartLoggerPtr;
+
+
+extern PartLogger GlobalLogger;
+
+
+/*
+** functions to define the way the logging is done.
+** They work globally; i.e. they determine the loggin for the whole program!
+*/
+
+void enable_syslog( const std::string& name, Facility facility= Facility::User );
+void enable_syslog( Facility facility );
+void enable_syslog( bool enable= true );
+
+void enable_stderr_log(bool enable= true );
+
+void enable_log_file( const std::string& name );
+void enable_log_file( bool enable= true );
+
+
+int set_log_level( int level );
+int get_log_level();
+bool has_log_level(int level);
+
+
+/*
+** char* versions .... *sigh*
+** ( are required, since the compiler doesn't automatically select the const std::string& versions... *big*sigh* )
+*/
+
+inline void enable_syslog( const char* name, Facility facility= Facility::User )
+{
+ enable_syslog( std::string(name), facility);
+}
+
+inline void enable_log_file( const char* name) { enable_log_file( std::string(name) ); }
+
+
+} // eo namespace Logger
+} // eo namespace I2n
+
+#endif
--- /dev/null
+/** @file
+ *
+ * @copyright © Copyright 2007-2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ */
+
+#include "source_track_basics.hpp"
+
+#include <list>
+#include <containerfunc.hpp>
+#include <stringfunc.hxx>
+#include <filefunc.hxx>
+
+
+namespace I2n
+{
+
+/*
+** implementation of SourceLocation
+*/
+
+SourceLocation::SourceLocation()
+: Line ( 0 )
+{
+} // eo SourceLocation::SourceLocation()
+
+
+SourceLocation::SourceLocation (
+ const std::string& file,
+ long line,
+ const std::string& funcname
+)
+: File( file )
+, Line( line )
+, FunctionName( funcname )
+{
+} // eo SourceLocation::SourceLocation(const std::string&,long,const std::string&)
+
+
+/**
+ * @brief returns a "location tag"; i.e. a string which can be used to identify
+ * the source location.
+ * @return the location tag.
+ */
+std::string SourceLocation::get_location_tag() const
+{
+ static std::list< std::string > suffixes= TransientPushBackFiller< std::string, std::list >()
+ ( ".cpp" ) ( ".cxx" ) ( ".cc" ) ( ".C" ) ( ".c++" )
+ ( ".hpp" ) ( ".hxx" ) ( ".hh" ) ( ".H" ) ( ".h++" ) ( ".h" )
+ ;
+ if ( LocationTag.empty() and not File.empty() )
+ {
+ std::string str= basename( File );
+ for( std::list< std::string >::const_iterator it= suffixes.begin();
+ it != suffixes.end();
+ ++it )
+ {
+ if ( has_suffix(str,*it) )
+ {
+ str= remove_suffix(str,*it);
+ break;
+ }
+ }
+ LocationTag= str;
+ LocationTag+= "#";
+ LocationTag+= to_string( Line );
+ }
+ return LocationTag;
+} // eo SourceLocation::get_location_tag()
+
+
+
+} // eo namespace I2n
--- /dev/null
+/** @file
+ *
+ * @copyright © Copyright 2007-2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ */
+
+#ifndef __I2N_COMMON_SOURCE_TRACK_BASICS_HPP__
+#define __I2N_COMMON_SOURCE_TRACK_BASICS_HPP__
+
+#include <string>
+#include <boost/current_function.hpp>
+
+/*
+** some helper macros
+*/
+
+/**
+ * macro which encapsulates the construction of a source location.
+ */
+#define HERE ::I2n::SourceLocation(__FILE__,__LINE__,BOOST_CURRENT_FUNCTION)
+
+
+namespace I2n
+{
+
+
+/**
+ * (helper) struct for providing a source location.
+ * Construction should be done with appropriate macros (like @a HERE)
+ */
+struct SourceLocation
+{
+ std::string File;
+ long Line;
+ std::string FunctionName;
+
+ SourceLocation();
+
+ SourceLocation(
+ const std::string& file,
+ long line,
+ const std::string& funcname);
+
+ operator bool() const
+ {
+ return Line>0 and not File.empty() and not FunctionName.empty();
+ } // eo operator bool
+
+ std::string get_function_name() const { return FunctionName; }
+ std::string get_filename() const { return File; }
+ long get_line_number() const { return Line; }
+
+ std::string get_location_tag() const;
+
+ private:
+
+ mutable std::string LocationTag;
+
+}; // eo struct SourceLocation
+
+
+
+
+} // eo namepsace I2n
+
+#endif
--- /dev/null
+/** @file
+ * @brief implementation of tracing functionality.
+ *
+ * @copyright © Copyright 2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ *
+ * @note This module is not thread safe!
+ * @todo make this module thread safe (only useful when we can use threads...)
+ */
+
+#include "tracefunc.hpp"
+
+#include <list>
+#include <vector>
+#include <sstream>
+
+
+namespace I2n
+{
+namespace Tracer
+{
+
+using Logger::GlobalLogger;
+
+
+namespace
+{
+
+typedef std::list< ScopeTracker* > ScopeTrackerList;
+
+ScopeTrackerList scope_tracker_list;
+
+
+std::vector< std::string > indents;
+
+
+/**
+ * @brief ensures indent level string to exist up to the desired level.
+ * @param level the desired indent level.
+ */
+void ensure_indent_level(int level)
+{
+ while (indents.size() <= level)
+ {
+ indents.push_back( indents.back() + " " );
+ }
+} // eo ensure_indent_level(int)
+
+
+/**
+ * @brief module initializer.
+ */
+class __Initializer
+{
+ public:
+ __Initializer()
+ {
+ // pre initialize indent strings:
+ indents.clear();
+ indents.reserve(10);
+ indents.push_back("");
+ for(int i=10; i-->0;)
+ {
+ indents.push_back( indents.back() + " " );
+ }
+ }
+} __initializer;
+
+
+} // eo namespace <anonymous>
+
+
+/*
+** implementation of ScopeTracker
+*/
+
+/**
+ * @brief constructor. initializes object with a source location and emits a ENTER message.
+ * @param loc the source location.
+ *
+ * the message is indented according to the current depth of nested ScopeTracker instances.
+ */
+ScopeTracker::ScopeTracker(
+ const SourceLocation& loc)
+: Location(loc)
+, Depth(0)
+, FuncDepth(0)
+{
+ if (!scope_tracker_list.empty())
+ {
+ ScopeTracker* last_tracker= scope_tracker_list.back();
+ if (Location)
+ {
+ if (last_tracker->Location
+ && last_tracker->Location.File == Location.File
+ && last_tracker->Location.FunctionName == Location.FunctionName)
+ {
+ FuncDepth= last_tracker->FuncDepth+1;
+ }
+ }
+ Depth= last_tracker->Depth + 1;
+ }
+ ensure_indent_level(Depth);
+ scope_tracker_list.push_back(this);
+ {
+ std::ostringstream ostr;
+ if (Location.FunctionName.empty())
+ {
+ ostr << "<unknown> (global scope?)";
+ }
+ else
+ {
+ ostr << Location.FunctionName;
+ if (FuncDepth>0)
+ {
+ ostr << "#" << FuncDepth+1;
+ }
+ }
+ Tag= ostr.str();
+ }
+ // spit a message
+ if (Logger::has_log_level(Logger::LogLevel::Debug))
+ {
+ GlobalLogger.debug() << indents[Depth] << "ENTER " << Tag;
+ }
+} // eo ScopeTrcaker::ScopeTracker(const SourceLocation&)
+
+
+/**
+ * @brief destructor. emits a LEAVE message.
+ *
+ *
+ */
+ScopeTracker::~ScopeTracker()
+{
+ // spit a message
+ if (Logger::has_log_level(Logger::LogLevel::Debug))
+ {
+ GlobalLogger.debug() << indents[Depth] << "LEAVE " << Tag;
+ }
+ if (scope_tracker_list.empty())
+ {
+ return;
+ }
+ if (scope_tracker_list.back() == this)
+ {
+ scope_tracker_list.pop_back();
+ }
+ else
+ {
+ // oh hell, this should never be the case!
+ //TODO
+ GlobalLogger.error() << "inconsistency detected in scope tracker";
+ }
+} // eo ScopeTracker::~ScopeTracker()
+
+
+
+
+} // eo namespace Tracer
+} // eo namespace I2n
--- /dev/null
+/** @file
+ * @brief provides tracing funtionality.
+ *
+ * Provides a scope tracker
+ *
+ * @copyright © Copyright 2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ */
+
+#ifndef __I2N_COMMON_TRACEFUNC_HPP__
+#define __I2N_COMMON_TRACEFUNC_HPP__
+
+#include <string>
+#include "logfunc.hpp"
+#include "source_track_basics.hpp"
+
+
+namespace I2n
+{
+namespace Tracer
+{
+
+
+/**
+ * @brief scope tracker class.
+ *
+ * basically: emits a ENTER message on construction and a LEAVE message on destruction.
+ * And indent these messages acoording to the nesting depth.
+ */
+class ScopeTracker
+{
+ public:
+ ScopeTracker(const SourceLocation& loc);
+ ~ScopeTracker();
+
+ private:
+ ScopeTracker(const ScopeTracker& rhs);
+ ScopeTracker& operator = (const ScopeTracker& rhs);
+
+ SourceLocation Location;
+ int Depth;
+ int FuncDepth;
+
+ std::string Tag;
+}; // eo ScopeTracker
+
+
+/*
+** helper macros:
+*/
+
+/**
+ * @brief constructs a scope tracker.
+ */
+#define SCOPETRACKER() ::I2n::Tracer::ScopeTracker __scope_tracker(HERE)
+
+
+} // eo namespace Tracer
+} // eo namespace I2n
+
+#endif
METASOURCES = AUTO
check_PROGRAMS = test
test_SOURCES = ip_range.cpp stringfunc.cpp test.cpp test_containerfunc.cpp \
- test_filefunc.cpp test_pidfile.cpp
+ test_filefunc.cpp test_logging.cpp test_pidfile.cpp
test_LDADD = $(top_builddir)/src/libi2ncommon.la @CPPUNIT_LIBS@
TESTS = test
--- /dev/null
+/** @file
+ * test cases for loggin module.
+ *
+ * (c) Copyright 2007 by Intra2net AG
+ *
+ * info@intra2net.com
+ */
+
+//#define NOISEDEBUG
+
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <exception>
+
+
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <logfunc.hpp>
+#include <tracefunc.hpp>
+
+
+#ifdef NOISEDEBUG
+#define DOUT(msg) std::cout << msg << std::endl
+#else
+#define DOUT(msg) do {} while (0)
+#endif
+
+
+using namespace CppUnit;
+
+using namespace I2n;
+
+namespace {
+
+Logger::PartLogger module_logger(HERE);
+
+} // eo namespace <anonymous>
+
+
+
+class TestLogging : public TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestLogging);
+
+ CPPUNIT_TEST(Syslog1);
+ CPPUNIT_TEST(TestScopeTrace1);
+
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void setUp()
+ {
+ } // eo setUp
+
+
+ void tearDown()
+ {
+ Logger::set_log_level(0);
+ Logger::enable_syslog(false);
+ Logger::enable_stderr_log(false);
+ Logger::enable_log_file(false);
+ } // eo tearDown
+
+
+ /*
+ * the tests:
+ */
+
+
+ void Syslog1()
+ {
+ //Logger::enable_syslog("I2N Unittest", Logger::Facility::User );
+ Logger::enable_syslog( Logger::Facility::User );
+ Logger::PartLogger log(__func__);
+
+ Logger::set_log_level( 7 );
+ Logger::enable_stderr_log();
+ Logger::enable_log_file("zzUnitTest.log");
+
+ log.error("Test error msg");
+ log.error() << "Stream test error msg #" << 2 << ".";
+ log.warning() << "Stream test warning msg";
+ log.notice() << "Stream test notice msg";
+ log.info() << "Stream test info msg";
+ log.debug() << "Stream test debug msg";
+
+ log.debug()
+ << "multiline log message" << std::endl
+ << "this (second) line should be indented" << std::endl
+ << "and this also!" << std::endl;
+ log.debug(HERE) << "This should have a source info";
+
+ module_logger.debug(HERE) << "module level debug message with source loc info";
+ } // eo Syslog1()
+
+
+
+ void TestScopeTrace1()
+ {
+ //Logger::enable_syslog("I2N Unittest", Logger::Facility::User );
+ Logger::enable_syslog( Logger::Facility::User );
+ Logger::PartLogger log(__func__);
+
+ Logger::set_log_level( 7 );
+ Logger::enable_stderr_log();
+ Logger::enable_log_file("zzUnitTest.log");
+
+ SCOPETRACKER();
+
+ log.notice() << "Stream test notice msg";
+ {
+ SCOPETRACKER(); // #2
+ {
+ SCOPETRACKER(); // #3
+ {
+ SCOPETRACKER(); // #4
+ }
+ }
+ {
+ SCOPETRACKER(); // #3
+ }
+ }
+ } // eo TestScopeTrace1()
+
+}; // eo class TestLogging
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestLogging);