/*
-Copyright (c) 2004-2007, John Hurst
+Copyright (c) 2004-2009, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#include <KM_util.h>
#include <stdarg.h>
#include <errno.h>
+#include <iosfwd>
+#include <set>
#define LOG_MSG_IMPL(t) \
va_list args; \
LOG_NOTICE, // application user info
LOG_ALERT, // application non-fatal or near-miss error
LOG_CRIT, // application fatal error
+ LOG_MAX
};
// OR these values together to come up with sink filter flags.
- // The default mask is 0x0000ffff (no time stamp, no pid, all messages).
- const i32_t LOG_ALLOW_TIMESTAMP = 0x01000000;
- const i32_t LOG_ALLOW_PID = 0x02000000;
-
- 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_DEFAULT = 0x00008000; // show messages having an unknown type
- const i32_t LOG_ALLOW_NONE = 0x00000000;
- const i32_t LOG_ALLOW_MESSAGES = 0x0000ffff;
- const i32_t LOG_ALLOW_ANY = 0xffffffff;
+ // 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
LogEntry(ui32_t pid, LogType_t t, const char* m) : PID(pid), Type(t), Msg(m) { assert(m); }
virtual ~LogEntry() {}
- bool CreateStringWithFilter(i32_t, std::string&) const;
+ // 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(); }
bool Unarchive(MemIOReader* Reader);
};
+ //
+ std::basic_ostream<char, std::char_traits<char> >&
+ operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry);
+
- typedef ArchivableList<LogEntry> LogEntryList_t;
+ typedef ArchivableList<LogEntry> LogEntryList;
//
class ILogSink
{
protected:
i32_t m_filter;
+ i32_t m_options;
+ Mutex m_lock;
+ std::set<ILogSink*> m_listeners;
+
+ // you must obtain m_lock BEFORE calling this from your own WriteEntry
+ void WriteEntryToListeners(const LogEntry& entry)
+ {
+ std::set<ILogSink*>::iterator i;
+ for ( i = m_listeners.begin(); i != m_listeners.end(); ++i )
+ (*i)->WriteEntry(entry);
+ }
+
+ KM_NO_COPY_CONSTRUCT(ILogSink);
public:
+ ILogSink() : m_filter(LOG_ALLOW_ALL), m_options(LOG_OPTION_NONE) {}
virtual ~ILogSink() {}
- void SetFilterFlags(i32_t f) { m_filter = f; }
- i32_t GetFilterFlags() const { return m_filter; }
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) != 0); }
+ 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); }
+
+ void AddListener(ILogSink& s) {
+ if ( &s != this )
+ {
+ AutoMutex l(m_lock);
+ m_listeners.insert(&s);
+ }
+ }
+
+ void DelListener(ILogSink& s) {
+ AutoMutex l(m_lock);
+ m_listeners.erase(&s);
+ }
// library messages
void Error(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ERROR); }
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;
+ // attach a log sink as a listener until deleted
+ class LogSinkListenContext
+ {
+ ILogSink* m_log_source;
+ ILogSink* m_sink;
+ KM_NO_COPY_CONSTRUCT(LogSinkListenContext);
+ LogSinkListenContext();
+
+ public:
+ LogSinkListenContext(ILogSink& source, ILogSink& sink)
+ {
+ m_log_source = &source;
+ m_sink = &sink;
+ m_log_source->AddListener(*m_sink);
+ }
+
+ ~LogSinkListenContext()
+ {
+ m_log_source->DelListener(*m_sink);
+ }
+ };
- 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_a.WriteEntry(Entry);
- }
- };
-
- // collect log messages into the given list
+ // collect log messages into the given list, does not test filter
class EntryListLogSink : public ILogSink
{
+ LogEntryList& m_Target;
KM_NO_COPY_CONSTRUCT(EntryListLogSink);
EntryListLogSink();
- LogEntryList_t& m_Target;
-
public:
- EntryListLogSink(LogEntryList_t& target) : m_Target(target) {}
+ EntryListLogSink(LogEntryList& target) : m_Target(target) {}
virtual ~EntryListLogSink() {}
- void WriteEntry(const LogEntry& Entry) {
- m_Target.push_back(Entry);
- }
+ void WriteEntry(const LogEntry& Entry);
};
// write messages to a POSIX stdio stream
class StdioLogSink : public ILogSink
{
- Mutex m_Lock;
FILE* m_stream;
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() {}
void WriteEntry(const LogEntry&);
// write messages to the Win32 debug stream
class WinDbgLogSink : public ILogSink
{
- Mutex m_Lock;
KM_NO_COPY_CONSTRUCT(WinDbgLogSink);
public:
// write messages to a POSIX file descriptor
class StreamLogSink : public ILogSink
{
- Mutex m_Lock;
int m_fd;
KM_NO_COPY_CONSTRUCT(StreamLogSink);
StreamLogSink();
void WriteEntry(const LogEntry&);
};
+
+ // write messages to the syslog facility
+ class SyslogLogSink : public ILogSink
+ {
+ KM_NO_COPY_CONSTRUCT(SyslogLogSink);
+ SyslogLogSink();
+
+ public:
+ SyslogLogSink(const std::string& source_name, int facility);
+ virtual ~SyslogLogSink();
+ void WriteEntry(const LogEntry&);
+ };
+
+ // convert a string into the appropriate syslog facility id
+ int SyslogNameToFacility(const std::string& facility_name);
+
#endif