/*
-Copyright (c) 2004-2006, John Hurst
+Copyright (c) 2004-2007, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#include <KM_platform.h>
#include <KM_mutex.h>
+#include <KM_util.h>
#include <stdarg.h>
#include <errno.h>
-#define LOG_MSG_IMPL(t) va_list args; va_start(args, fmt); vLogf((t), fmt, &args); va_end(args)
-
-
+#define LOG_MSG_IMPL(t) \
+ va_list args; \
+ va_start(args, fmt); \
+ vLogf((t), fmt, &args); \
+ va_end(args)
// Returns RESULT_PTR if the given argument is NULL.
# define KM_TEST_NULL_L(p) \
//---------------------------------------------------------------------------------
// message logging
- // Error and debug messages will be delivered to an object having this interface.
- // The default implementation sends only LOG_ERROR and LOG_WARN messages to stderr.
- // To receive LOG_INFO or LOG_DEBUG messages, or to send messages somewhere other
- // than stderr, implement this interface and register an instance of your new class
- // by calling SetDefaultLogSink().
+ // Log messages are recorded by objects which implement the interface given
+ // in the class ILogSink below. The library maintains a pointer to a default
+ // log sink which is used by the library to report messages.
+ //
+
+ // types of log messages
+ enum LogType_t {
+ LOG_DEBUG, // detailed developer info
+ LOG_INFO, // developer info
+ LOG_WARN, // library non-fatal or near-miss error
+ LOG_ERROR, // library fatal error
+ LOG_NOTICE, // application user info
+ LOG_ALERT, // application non-fatal or near-miss error
+ LOG_CRIT, // application fatal error
+ };
+
+
+ // OR these values together to come up with sink filter flags.
+ // The default mask is LOG_ALLOW_ALL (all messages).
+ const i32_t LOG_ALLOW_DEBUG = 0x00000001;
+ const i32_t LOG_ALLOW_INFO = 0x00000002;
+ const i32_t LOG_ALLOW_WARN = 0x00000004;
+ const i32_t LOG_ALLOW_ERROR = 0x00000008;
+ const i32_t LOG_ALLOW_NOTICE = 0x00000010;
+ const i32_t LOG_ALLOW_ALERT = 0x00000020;
+ const i32_t LOG_ALLOW_CRIT = 0x00000040;
+ const i32_t LOG_ALLOW_NONE = 0x00000000;
+ const i32_t LOG_ALLOW_ALL = 0x000fffff;
+
+ // options are used to control display format default is 0.
+ const i32_t LOG_OPTION_TYPE = 0x01000000;
+ const i32_t LOG_OPTION_TIMESTAMP = 0x02000000;
+ const i32_t LOG_OPTION_PID = 0x04000000;
+ const i32_t LOG_OPTION_NONE = 0x00000000;
+ const i32_t LOG_OPTION_ALL = 0xfff00000;
+
+ // A log message with environmental metadata
+ class LogEntry : public IArchive
+ {
+ public:
+ ui32_t PID;
+ Timestamp EventTime;
+ LogType_t Type;
+ std::string Msg;
+
+ LogEntry() {}
+ LogEntry(ui32_t pid, LogType_t t, const char* m) : PID(pid), Type(t), Msg(m) { assert(m); }
+ virtual ~LogEntry() {}
+
+ // returns true if the message Type is present in the mask
+ bool TestFilter(i32_t mask_value) const;
+
+ // renders the message into outstr using the given dispaly options
+ // returns outstr&
+ std::string& CreateStringWithOptions(std::string& outstr, i32_t mask_value) const;
+
+ // IArchive
+ bool HasValue() const { return ! Msg.empty(); }
+ ui32_t ArchiveLength() const;
+ bool Archive(MemIOWriter* Writer) const;
+ bool Unarchive(MemIOReader* Reader);
+ };
+
+
+ typedef ArchivableList<LogEntry> LogEntryList;
+
+ //
class ILogSink
{
- public:
- enum LogType_t { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR,
- LOG_NOTICE, LOG_ALERT, LOG_CRIT };
+ protected:
+ i32_t m_filter;
+ i32_t m_options;
+ public:
+ ILogSink() : m_filter(LOG_ALLOW_ALL), m_options(LOG_OPTION_NONE) {}
virtual ~ILogSink() {}
- void Critical(const char* fmt, ...) { LOG_MSG_IMPL(LOG_CRIT); }
- void Alert(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ALERT); }
- void Notice(const char* fmt, ...) { LOG_MSG_IMPL(LOG_NOTICE); }
+ void SetFilterFlag(i32_t f) { m_filter |= f; }
+ void UnsetFilterFlag(i32_t f) { m_filter &= ~f; }
+ bool TestFilterFlag(i32_t f) const { return ((m_filter & f) == f); }
+
+ void SetOptionFlag(i32_t o) { m_options |= o; }
+ void UnsetOptionFlag(i32_t o) { m_options &= ~o; }
+ bool TestOptionFlag(i32_t o) const { return ((m_options & o) == o); }
+
+ // library messages
void Error(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ERROR); }
void Warn(const char* fmt, ...) { LOG_MSG_IMPL(LOG_WARN); }
void Info(const char* fmt, ...) { LOG_MSG_IMPL(LOG_INFO); }
void Debug(const char* fmt, ...) { LOG_MSG_IMPL(LOG_DEBUG); }
- void Logf(ILogSink::LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); }
- virtual void vLogf(LogType_t, const char*, va_list*) = 0; // log a formatted string with a va_list struct
+
+ // application messages
+ void Critical(const char* fmt, ...) { LOG_MSG_IMPL(LOG_CRIT); }
+ void Alert(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ALERT); }
+ void Notice(const char* fmt, ...) { LOG_MSG_IMPL(LOG_NOTICE); }
+
+ // message with type
+ void Logf(LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); }
+
+ // actual log sink input
+ virtual void vLogf(LogType_t, const char*, va_list*);
+ virtual void WriteEntry(const LogEntry&) = 0;
};
+
// Sets the internal default sink to the given receiver. If the given value
// is zero, sets the default sink to the internally allocated stderr sink.
void SetDefaultLogSink(ILogSink* = 0);
// Returns the internal default sink.
ILogSink& DefaultLogSink();
+
+ // Sets a log sink as the default until the object is destroyed.
+ // The original default sink is saved and then restored on delete.
+ class LogSinkContext
+ {
+ KM_NO_COPY_CONSTRUCT(LogSinkContext);
+ LogSinkContext();
+ ILogSink* m_orig;
+
+ public:
+ LogSinkContext(ILogSink& sink) {
+ m_orig = &DefaultLogSink();
+ SetDefaultLogSink(&sink);
+ }
+
+ ~LogSinkContext() {
+ SetDefaultLogSink(m_orig);
+ }
+ };
+
+ //------------------------------------------------------------------------------------------
//
+
+ // write messages to two subordinate log sinks
+ class TeeLogSink : public ILogSink
+ {
+ KM_NO_COPY_CONSTRUCT(TeeLogSink);
+ TeeLogSink();
+
+ ILogSink& m_a;
+ ILogSink& m_b;
+
+ public:
+ TeeLogSink(ILogSink& a, ILogSink& b) : m_a(a), m_b(b) {}
+ virtual ~TeeLogSink() {}
+
+ void WriteEntry(const LogEntry& Entry) {
+ m_a.WriteEntry(Entry);
+ m_b.WriteEntry(Entry);
+ }
+ };
+
+ // collect log messages into the given list, does not test filter
+ class EntryListLogSink : public ILogSink
+ {
+ Mutex m_Lock;
+ LogEntryList& m_Target;
+ KM_NO_COPY_CONSTRUCT(EntryListLogSink);
+ EntryListLogSink();
+
+ public:
+ EntryListLogSink(LogEntryList& target) : m_Target(target) {}
+ virtual ~EntryListLogSink() {}
+
+ void WriteEntry(const LogEntry& Entry);
+ };
+
+
+ // write messages to a POSIX stdio stream
class StdioLogSink : public ILogSink
{
Mutex m_Lock;
KM_NO_COPY_CONSTRUCT(StdioLogSink);
public:
- StdioLogSink() : m_stream(stderr) {};
- StdioLogSink(FILE* stream) : m_stream(stream) {}
+ StdioLogSink() : m_stream(stderr) {}
+ StdioLogSink(FILE* stream) : m_stream(stream) {}
virtual ~StdioLogSink() {}
- virtual void vLogf(LogType_t, const char*, va_list*);
+
+ void WriteEntry(const LogEntry&);
};
#ifdef KM_WIN32
- //
+ // write messages to the Win32 debug stream
class WinDbgLogSink : public ILogSink
{
Mutex m_Lock;
public:
WinDbgLogSink() {}
virtual ~WinDbgLogSink() {}
- virtual void vLogf(LogType_t, const char*, va_list*);
- };
-#else
+ void WriteEntry(const LogEntry&);
+ };
+#endif
- //
+#ifndef KM_WIN32
+ // write messages to a POSIX file descriptor
class StreamLogSink : public ILogSink
{
Mutex m_Lock;
public:
StreamLogSink(int fd) : m_fd(fd) {}
virtual ~StreamLogSink() {}
- virtual void vLogf(LogType_t, const char*, va_list*);
+
+ void WriteEntry(const LogEntry&);
};
#endif
+
} // namespace Kumu
#endif // _KM_LOG_H_