diff options
Diffstat (limited to 'src/syncevo/Logging.h')
-rw-r--r-- | src/syncevo/Logging.h | 205 |
1 files changed, 161 insertions, 44 deletions
diff --git a/src/syncevo/Logging.h b/src/syncevo/Logging.h index 283efa8d..dde9e325 100644 --- a/src/syncevo/Logging.h +++ b/src/syncevo/Logging.h @@ -33,8 +33,11 @@ #endif #include <syncevo/Timespec.h> +#include <syncevo/ThreadSupport.h> #include <boost/function.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> #include <syncevo/declarations.h> SE_BEGIN_CXX @@ -130,8 +133,17 @@ class Logger * * Included by LoggerStdout in the [INFO/DEBUG/...] tag. */ - static void setProcessName(const std::string &name) { m_processName = name; } - static std::string getProcessName() { return m_processName; } + static void setProcessName(const std::string &name); + static std::string getProcessName(); + + /** + * Obtains the recursive logging mutex. + * + * All calls offered by the Logger class already lock that mutex + * internally, but sometimes it may be necessary to protect a larger + * region of logging related activity. + */ + static RecMutex::Guard lock(); #ifdef HAVE_GLIB /** @@ -161,6 +173,15 @@ class Logger virtual ~Logger(); /** + * Prepare logger for removal from logging stack. May be called + * multiple times. + * + * The logger should stop doing anything right away and just pass + * on messages until it gets deleted eventually. + */ + virtual void remove() throw () {} + + /** * Collects all the parameters which may get passed to * messagev. */ @@ -199,36 +220,69 @@ class Logger const char *format, va_list args) = 0; - /** redirect into messagev() */ - void message(Level level, - const std::string *prefix, - const char *file, - int line, - const char *function, - const char *format, - ...) + /** + * A convenience and backwards-compatibility class which allows + * calling some methods of the underlying pointer directly similar + * to the Logger reference returned in previous SyncEvolution + * releases. + */ + class Handle + { + boost::shared_ptr<Logger> m_logger; + + public: + Handle() throw (); + Handle(Logger *logger) throw (); + template<class L> Handle(const boost::shared_ptr<L> &logger) throw () : m_logger(logger) {} + template<class L> Handle(const boost::weak_ptr<L> &logger) throw () : m_logger(logger.lock()) {} + Handle(const Handle &other) throw (); + Handle &operator = (const Handle &other) throw (); + ~Handle() throw (); + + operator bool () const { return m_logger; } + bool operator == (Logger *logger) const { return m_logger.get() == logger; } + Logger *get() const { return m_logger.get(); } + + void messagev(const MessageOptions &options, + const char *format, + va_list args) + { + m_logger->messagev(options, format, args); + } + + void message(Level level, + const std::string *prefix, + const char *file, + int line, + const char *function, + const char *format, + ...) #ifdef __GNUC__ - __attribute__((format(printf, 7, 8))) + __attribute__((format(printf, 7, 8))) #endif - ; - void message(Level level, - const std::string &prefix, - const char *file, - int line, - const char *function, - const char *format, - ...) + ; + void message(Level level, + const std::string &prefix, + const char *file, + int line, + const char *function, + const char *format, + ...) #ifdef __GNUC__ - __attribute__((format(printf, 7, 8))) + __attribute__((format(printf, 7, 8))) #endif - ; - void messageWithOptions(const MessageOptions &options, - const char *format, - ...) + ; + void messageWithOptions(const MessageOptions &options, + const char *format, + ...) #ifdef __GNUC__ - __attribute__((format(printf, 3, 4))) + __attribute__((format(printf, 3, 4))) #endif - ; + ; + void setLevel(Level level) { m_logger->setLevel(level); } + Level getLevel() { return m_logger->getLevel(); } + void remove() throw () { m_logger->remove(); } + }; /** * Grants access to the singleton which implements logging. @@ -236,31 +290,25 @@ class Logger * class itself is platform specific: if no Log instance * has been set yet, then this call has to create one. */ - static Logger &instance(); + static Handle instance(); /** - * Overrides the default Logger implementation. The Logger class - * itself will never delete the active logger. + * Overrides the current default Logger implementation. * * @param logger will be used for all future logging activities */ - static void pushLogger(Logger *logger); + static void addLogger(const Handle &logger); /** - * Remove the current logger and restore previous one. - * Must match a pushLogger() call. - */ - static void popLogger(); - - /** total number of active loggers */ - static int numLoggers(); - - /** - * access to active logger - * @param index 0 for oldest (inner-most) logger - * @return pointer or NULL for invalid index + * Remove the specified logger. + * + * Note that the logger might still be in use afterwards, for + * example when a different thread currently uses it. Therefore + * loggers should be small stub classes. If they need access to + * more expensive classes to do their work, they shold hold weak + * reference to those and only lock them when logging. */ - static Logger *loggerAt(int index); + static void removeLogger(Logger *logger); virtual void setLevel(Level level) { m_level = level; } virtual Level getLevel() { return m_level; } @@ -288,7 +336,6 @@ class Logger boost::function<void (std::string &chunk, size_t expectedTotal)> print); private: - static std::string m_processName; Level m_level; /** @@ -299,6 +346,76 @@ class Logger Timespec m_startTime; }; +/** + * Takes a logger and adds it to the stack + * as long as the instance exists. + */ +template<class L> class PushLogger : boost::noncopyable +{ + Logger::Handle m_logger; + + public: + PushLogger() {} + /** + * Can use Handle directly here. + */ + PushLogger(const Logger::Handle &logger) : m_logger(logger) + { + if (m_logger) { + Logger::addLogger(m_logger); + } + } + /** + * Take any type that a Handle constructor accepts, then use it as + * Handle. + */ + template <class M> PushLogger(M logger) : m_logger(Logger::Handle(logger)) + { + if (m_logger) { + Logger::addLogger(m_logger); + } + } + ~PushLogger() throw () + { + if (m_logger) { + Logger::removeLogger(m_logger.get()); + } + } + + operator bool () const { return m_logger; } + + void reset(const Logger::Handle &logger) + { + if (m_logger) { + Logger::removeLogger(m_logger.get()); + } + m_logger = logger; + if (m_logger) { + Logger::addLogger(m_logger); + } + } + template<class M> void reset(M logger) + { + if (m_logger) { + Logger::removeLogger(m_logger.get()); + } + m_logger = Logger::Handle(logger); + if (m_logger) { + Logger::addLogger(m_logger); + } + } + + void reset() + { + if (m_logger) { + Logger::removeLogger(m_logger.get()); + } + m_logger = Logger::Handle(); + } + + L *get() { return static_cast<L *>(m_logger.get()); } + L * operator -> () { return get(); } +}; /** * Wraps Logger::message() in the current default logger. |