public:
    BinLogMsgHandler(const char * _filename, bool _append = false);
    virtual ~BinLogMsgHandler();
    IMPLEMENT_IINTERFACE;
    void                      handleMessage(const LogMsg & msg);
    bool                      needsPrep() const { return false; }
    void                      prep() {}
    void                      addToPTree(IPropertyTree * tree) const;
    unsigned                  queryMessageFields() const { return MSGFIELD_all; }
    void                      setMessageFields(unsigned _fields) {}
    int                       flush() { return 0; }
    char const *              disable();
    void                      enable();
    bool                      getLogName(StringBuffer &name) const { name.append(filename); return true; }
    offset_t                  getLogPosition(StringBuffer &name) const { CriticalBlock block(crit); name.append(filename); return fstr->tell(); }
protected:
    StringAttr                filename;
    bool                      append;
    OwnedIFile                file;
    OwnedIFileIO              fio;
    OwnedIFileIOStream        fstr;
    mutable MemoryBuffer      mbuff;
    mutable size32_t              msglen;
    mutable CriticalSection   crit;
};

// Implementation of handler which uses the audit event logger

class SysLogMsgHandler : implements ILogMsgHandler, public CInterface
{
public:
    SysLogMsgHandler(ISysLogEventLogger * _logger, unsigned _fields) : logger(_logger), fields(_fields) {}
    IMPLEMENT_IINTERFACE;
    void                      handleMessage(const LogMsg & msg);
    bool                      needsPrep() const { return false; }
    void                      prep() {}
    void                      addToPTree(IPropertyTree * tree) const;
    unsigned                  queryMessageFields() const { return fields; }
    void                      setMessageFields(unsigned _fields) { fields = _fields; }
    int                       flush() { return 0; }
    char const *              disable() { return "Audit"; }
    void                      enable() {}
    bool                      getLogName(StringBuffer &name) const { return false; }
    offset_t                  getLogPosition(StringBuffer &logFileName) const { return 0; }
protected:
    ISysLogEventLogger *      logger;
    unsigned                  fields;
};

// Monitor to watch for messages --- pairs up a filter with a handler

class LogMsgMonitor : public CInterface
{
public:
    LogMsgMonitor(ILogMsgFilter * _filter, ILogMsgHandler * _handler) : filter(_filter), handler(_handler) {}
    void                      processMessage(const LogMsg & msg) { if(filter->includeMessage(msg)) handler->handleMessage(msg); }
    ILogMsgFilter *           queryFilter() const { return filter; }
    ILogMsgFilter *           getFilter() const { return LINK(filter); }
    ILogMsgHandler *          queryHandler() const { return handler; }
    ILogMsgHandler *          getHandler() const { return LINK(handler); }
    void                      setFilter(ILogMsgFilter * newFilter) { filter.set(newFilter); }
    void                      setFilterOwn(ILogMsgFilter * newFilter) { filter.setown(newFilter); }
    void                      addToPTree(IPropertyTree * tree) const;
private:
    Linked<ILogMsgFilter>     filter;
    Linked<ILogMsgHandler>    handler;
};

class DropLogMsg;

// Implementation of logging manager

class CLogMsgManager : public ILogMsgManager, public CInterface
{
private:
    class MsgProcessor : public Thread
    {
    public:
        MsgProcessor(CLogMsgManager * _owner) : Thread("CLogMsgManager::MsgProcessor"), owner(_owner), more(true), droppingLimit(0) {}
        void push(LogMsg * msg);
        virtual int run();
        void notify(LogMsg * msg);
        void stop();
        void setBlockingLimit(unsigned lim);
        void setDroppingLimit(unsigned lim, unsigned num);
        void resetLimit();
        bool flush(unsigned timeout);

    private:
        void drop();

    private:
        CLogMsgManager * owner;
        bool more;
        CallbackInterThreadQueueOf<LogMsg, MsgProcessor, false> q;
        unsigned droppingLimit;
        unsigned numToDrop = 1;
        Mutex pullCycleMutex;
    };
    Owned<MsgProcessor> processor;
    friend class MsgProcessor;
    friend class DropLogMsg;

public:
    CLogMsgManager() : prefilter(0, 0, 0, false), nextID(0), suspendedChildren(false), port(0), session(UnknownSession) { }
    ~CLogMsgManager();
    IMPLEMENT_IINTERFACE;
    void                      enterQueueingMode();
    void                      setQueueBlockingLimit(unsigned lim);
    void                      setQueueDroppingLimit(unsigned lim, unsigned numToDrop);
    void                      resetQueueLimit();
    bool                      flushQueue(unsigned timeout) { if(processor) return processor->flush(timeout); else return true; }
    void                      report(const LogMsgCategory & cat, const char * format,...) __attribute__((format(printf,3,4)));
    void                      report_va(const LogMsgCategory & cat, const char * format, va_list args) __attribute__((format(printf,3,0)));
    void                      report(const LogMsgCategory & cat, LogMsgCode code, const char * format,...) __attribute__((format(printf,4,5)));
    void                      report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args) __attribute__((format(printf,4,0)));
    void                      report(const LogMsgCategory & cat, const IException * e, const char * prefix = NULL);
    void                      report(unsigned compo, const LogMsgCategory & cat, const char * format,...) __attribute__((format(printf,4,5)));
    void                      report_va(unsigned compo, const LogMsgCategory & cat, const char * format, va_list args) __attribute__((format(printf,4,0)));
    void                      report(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format,...) __attribute__((format(printf,5,6)));
    void                      report_va(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args) __attribute__((format(printf,5,0)));
    void                      report(unsigned compo, const LogMsgCategory & cat, const IException * e, const char * prefix = NULL);
    void                      report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format,...) __attribute__((format(printf,4,5)));
    void                      report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args) __attribute__((format(printf,4,0)));
    void                      report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format,...) __attribute__((format(printf,5,6)));
    void                      report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args) __attribute__((format(printf,5,0)));
    void                      report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * e, const char * prefix = NULL);
    void                      report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format,...) __attribute__((format(printf,5,6)));
    void                      report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args) __attribute__((format(printf,5,0)));
    void                      report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format,...) __attribute__((format(printf,6,7)));
    void                      report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)__attribute__((format(printf,6,0)));
    void                      report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * e, const char * prefix = NULL);
    void                      report(const LogMsg & msg) const { if(prefilter.includeCategory(msg.queryCategory())) doReport(msg); }
