X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FKM_log.h;h=fb8d805f63c87db86a331f00495aa0dbe532d5f4;hb=71e5dbde64e9186cfd5de462553485612218d6fc;hp=2bbc330b2758fb4cc3376221762d5a4b55609988;hpb=bfedf725dac9d13f3a02fe69f45c302ab29d2b1e;p=asdcplib.git diff --git a/src/KM_log.h b/src/KM_log.h index 2bbc330..fb8d805 100755 --- a/src/KM_log.h +++ b/src/KM_log.h @@ -1,5 +1,5 @@ /* -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 @@ -35,10 +35,33 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include -#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) \ + if ( (p) == 0 ) { \ + DefaultLogSink().Error("NULL pointer in file %s, line %d\n", __FILE__, __LINE__); \ + return Kumu::RESULT_PTR; \ + } + +// Returns RESULT_PTR if the given argument is NULL. It then +// assumes that the argument is a pointer to a string and returns +// RESULT_NULL_STR if the first character is '\0'. +// +# define KM_TEST_NULL_STR_L(p) \ + KM_TEST_NULL_L(p); \ + if ( (p)[0] == '\0' ) { \ + DefaultLogSink().Error("Empty string in file %s, line %d\n", __FILE__, __LINE__); \ + return Kumu::RESULT_NULL_STR; \ + } namespace Kumu @@ -49,30 +72,111 @@ namespace Kumu //--------------------------------------------------------------------------------- // 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 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); @@ -80,7 +184,65 @@ namespace Kumu // 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; @@ -88,14 +250,15 @@ namespace Kumu 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; @@ -104,12 +267,13 @@ namespace Kumu 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; @@ -120,10 +284,12 @@ namespace Kumu 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_