// snfLOGmgr.hpp
//
// (C) Copyright 2006 - 2009 ARM Research Labs, LLC.
// See www.armresearch.com for the copyright terms.
//
// SNF Logging and Statistics engine.

////////////////////////////////////////////////////////////////////////////////
//// Begin snfLOGmgr include only once

#ifndef snfLOGmgr_included
#define snfLOGmgr_included

#include <list>
#include <set>
#include <string>
#include <vector>
#include <sstream>
#include <ctime>
#include <cstdio>

#include "timing.hpp"
#include "threading.hpp"
#include "snf_match.h"

#include "snfCFGmgr.hpp"
#include "snfNETmgr.hpp"
#include "GBUdb.hpp"

#include "histogram.hpp"

class snfNETmgr;                                                                // Declare snfNETmgr
extern const char* SNF_ENGINE_VERSION;                                          // Declare the Engine Version Data

using namespace std;

//// DiscLogger ////////////////////////////////////////////////////////////////
// Writes log files back to Disc and double buffers data to minimize contention
// and delays. So - if it takes a few milliseconds to post the log to disc, the
// application that post()s to the log does not have to wait. Write back happens
// about once per second when enabled. Files can be appended or overwritten.

class DiscLogger : private Thread {                                             // Double buffered lazy writer.
  private:
    Mutex BufferControlMutex;                                                   // Protects buffers while swapping.
    Mutex FlushMutex;                                                           // Protects flush operations.
    string myPath;                                                              // Where the file should be written.
    string BufferA;                                                             // Log data buffer A.
    string BufferB;                                                             // Log data buffer B.
    bool UseANotB;                                                              // Indicates the active buffer.
    bool isDirty;                                                               // True if data not yet written.
    bool isBad;                                                                 // True if last write failed.
    bool isTimeToStop;                                                          // True when shutting down.
    bool inAppendMode;                                                          // True when in append mode.
    string& FlushingBuffer() { return ((UseANotB)?BufferA:BufferB); }           // Returns the buffer for flushing.
    string& PostingBuffer()  { return ((UseANotB)?BufferB:BufferA); }           // Returns the buffer for posting.
    bool isEnabled;                                                             // True when this should run.
    void myTask();                                                              // Write back thread task.

  public:
    DiscLogger(string N = "UnNamed");                                           // Constructs and starts the thread.
    ~DiscLogger();                                                              // Flushes and stops the thread.

    string Path(const string PathName) {                                        // Sets the file path.
        ScopeMutex NewSettings(BufferControlMutex);
        myPath = PathName;
        return myPath;
    }
    string Path() {                                                             // Returns the file path.
        ScopeMutex DontMove(BufferControlMutex);
        return myPath;
    }

    bool AppendMode(const bool AppendNotOverwrite) {                            // Sets append mode if true.
        return (inAppendMode = AppendNotOverwrite);
    }
    bool AppendMode() { return (inAppendMode); }                                // True if in append mode.

    bool OverwriteMode(const bool OverwriteNotAppend) {                         // Sets overwrite mode if true.
        return (inAppendMode = (!OverwriteNotAppend));
    }
    bool OverwriteMode() { return (!inAppendMode); }                            // True if in overwrite mode.

    void post(const string Input, const string NewPath = "");                   // Post Input to log, [set path].
    void flush();                                                               // Flush right now!
    bool Bad() { return (isBad); }                                              // True if last write failed.
    bool Good() { return (!isBad); }                                            // True if not Bad();
    bool Dirty() { return (isDirty); }                                          // True if data needs to be written.
    bool Enabled(const bool MakeEnabled) { return (isEnabled = MakeEnabled); }  // Enables writing if true.
    bool Enabled() { return (isEnabled); }                                      // True if enabled.

    const static ThreadType Type;                                               // The thread's type.

    const static ThreadState DiscLogger_Flush;                                  // Flushing state.
    const static ThreadState DiscLogger_Wait;                                   // Waiting state.

};

//// IPTestRecord //////////////////////////////////////////////////////////////
// Contains a complete analysis of a given IP. snf_RulebaseHandler provides a
// test facility that accepts and processes IPTestRecord objects. The calling
// process can then submit the IPTestRecord along with it's action to the
// snfLOGmgr for logging.

class IPTestRecord {                                                            // IP Analysis Record.
  public:
    IP4Address IP;                                                              // The IP to be tested.
    GBUdbRecord G;                                                              // The GBUdb Record for the IP.
    snfIPRange R;                                                               // The GBUdb classification (range).
    int Code;                                                                   // Code associated with Range.
    IPTestRecord(IP4Address testIP) : IP(testIP), Code(0) {}                    // Construct with an IP.
};

//// snfScanData ///////////////////////////////////////////////////////////////
// Contains testing data for a message.
// It's defined here in the LOGmgr module because this is the module that must
// log and collect statistics for each scanned message. The snfScanData object
// is the standardized way each engine reports it's scan results to snfLOGmgr.

const int MaxIPsPerMessage = 50;                                                // Maximum number of IPs to scan per message.

struct IPScanRecord {                                                           // Structure for IP scan results.
    int Ordinal;                                                                // Which IP starting with zero.
    unsigned int IP;                                                            // What is the IP.
    GBUdbRecord GBUdbData;                                                      // GBUdb data.
};

class snfScanData {                                                             // Scan Data record for each message.

  private:

    IPScanRecord MyIPScanData[MaxIPsPerMessage];                                // Array of IP scan results.
    int MyIPCount;                                                              // Count of IP scan results.
    bool DrillDownFlags[MaxIPsPerMessage];                                      // DrillDown flags. (Set Ignore).

    int SourceIPOrdinal;                                                        // Ordinal to source IP scan data.
    bool SourceIPFoundFlag;                                                     // True if source IP is set.
    snfIPRange SourceIPRangeFlag;                                               // GBUdb detection range for source IP.

    IP4Address myCallerForcedSourceIP;                                          // Caller forced source IP if not 0UL.
    IP4Address myHeaderDirectiveSourceIP;                                       // Header forced source IP if not 0UL.

  public:

    snfScanData(int ScanHorizon);                                               // Constructor.
    ~snfScanData();                                                             // Destructor.

    // The ReadyToClear bit helps multi-phase input situations where the first
    // phase might add some input data before calling the base-level scanner.
    // In those cases, the pre-scan-phase will clear() the ScanData (and with
    // it the ReadyToClear bit) before adding a few critical pieces of data -
    // such as the scan name and the scan-start UTC for example. When the base
    // level scanner is called to perform the actual scan, the clear() call
    // will be inert so that any pre-set data will be preserved.

    bool ReadyToClear;                                                          // True when Logging is done.
    void clear();                                                               // Clear for a new message.

    class NoFreeIPScanRecords {};                                               // Thrown when we run out of scan records.
    class OutOfBounds {};                                                       // Thrown in IPScanData if no record at i.

    int IPScanCount();                                                          // Return the number of IPs.
    IPScanRecord& newIPScanRecord();                                            // Get the next free IP scan record.
    IPScanRecord& IPScanData(int i);                                            // Return the IP scan record i.

    // 20080221 _M We can now define in header directives patterns for Received
    // headers that we should drill past if they show up as a message source
    // candidate. This allows GBUdb to learn to ignore certain IPs automatically
    // as they arrive either by IP stubs such as "[12.34.56." or by reverse DNS
    // data such as "friendly.example.com [". When the header directives engine
    // scans the headers it will call drillPastOrdinal for any Received header
    // that matches a <drilldown/> directive. Later when the header analysis
    // engine tries to pick the source for the message it will check each source
    // candidate against the isDrillDownSource() method. If the source is to be
    // ignored then it will set the ignore flag for that IP, process it as if
    // it were ignored, and continue searching for the actual source.

    void drillPastOrdinal(int O);                                               // Sets Drill Down flag for IP record O.
    bool isDrillDownSource(IPScanRecord& X);                                    // True if we drill through this source.

    IP4Address HeaderDirectiveSourceIP(IP4Address A);                           // set Header directive source IP.
    IP4Address HeaderDirectiveSourceIP();                                       // get Header directive source IP.
    IP4Address CallerForcedSourceIP(IP4Address A);                              // set Caller forced source IP.
    IP4Address CallerForcedSourceIP();                                          // get Caller forced source IP.

    IPScanRecord& SourceIPRecord(IPScanRecord& X);                              // Sets the source IP record.
    IPScanRecord& SourceIPRecord();                                             // Gets the source IP record.
    bool FoundSourceIP();                                                       // True if the source IP record was set.
    snfIPRange SourceIPRange();                                                 // GET Source IP range.
    snfIPRange SourceIPRange(snfIPRange R);                                     // SET Source IP range for this scan.

    // Direct access data...

    string SourceIPEvaluation;                                                  // GBUdb Source IP evaluation.

    // LogControl and General Message Flags

    time_t StartOfJobUTC;                                                       // Timestamp at start of job.
    int SetupTime;                                                              // Time in ms spent setting up to scan.
    string ScanName;                                                            // Identifying name or message file name.
    Timer ScanTime;                                                             // Scan time in ms.
    int ScanDepth;                                                              // Scan Depth in evaluators.

    string ClassicLogText;                                                      // Classic log entry text if any.
    string XMLLogText;                                                          // XML log entry text if any.
    string XHDRsText;                                                           // XHeaders text if any.
    bool XHeaderInjectOn;                                                       // True if injecting headers is on.
    bool XHeaderFileOn;                                                         // True if creating .xhdr file is on.

    bool MessageFileTypeCGPOn;                                                  // Expect a CGP type message file.

    int ScanSize;                                                               // What size is the scan request.

    // GBUdb Activity Flags

    bool GBUdbNormalTriggered;                                                  // True if GBUdb indeterminate IP source.

    bool GBUdbWhiteTriggered;                                                   // True if GBUdb found source IP white.
    bool GBUdbWhiteSymbolForced;                                                // True if white was on and symbol was set.
    bool GBUdbPatternSourceConflict;                                            // True if pattern was found with white IP.
    bool GBUdbAutoPanicTriggered;                                               // True if autopanic was triggered.
    bool GBUdbAutoPanicExecuted;                                                // True if an autopanic was added.

    bool GBUdbBlackTriggered;                                                   // True if GBUdb found source IP black.
    bool GBUdbBlackSymbolForced;                                                // True if black was on and symbol was set.
    bool GBUdbTruncateTriggered;                                                // True if Truncate was possible.
    bool GBUdbPeekTriggered;                                                    // True if we could peek.
    bool GBUdbSampleTriggered;                                                  // True if we could sample.
    bool GBUdbTruncateExecuted;                                                 // True if we actually did truncate.
    bool GBUdbPeekExecuted;                                                     // True if we peeked instead of truncating.
    bool GBUdbSampleExecuted;                                                   // True if we sampled.

    bool GBUdbCautionTriggered;                                                 // True if GBUdb found source IP suspicous.
    bool GBUdbCautionSymbolForced;                                              // True if caution was on and symbol was set.

    // Rule panics

    set<int> RulePanics;                                                        // A list of rule IDs panicked this scan.

    // Pattern Engine Scan Result Data

    vector<unsigned char> FilteredData;                                         // Message data after filter chain.
    unsigned long int HeaderDirectiveFlags;                                     // Flags set by header directives.

    bool PatternWasFound;                                                       // True if the pattern engine matched.
    int PatternID;                                                              // The winning rule ID.
    int PatternSymbol;                                                          // The associated symbol.

    list<snf_match> MatchRecords;                                               // List of match records.
    list<snf_match>::iterator MatchRecordsCursor;                               // Localized iterator for match records.
    int MatchRecordsDelivered;                                                  // Match records seen so far.

    int CompositeFinalResult;                                                   // What the scan function returned.

};

//// SMHDMY counter
//
// Provides a running SUM for a series of sliding windows. The input() expects
// a new piece of data every second (or so). It is presumed that another counter
// will keep track of the actual milliseconds if accuracy is required. The object
// is all primative data parts so it is possible to store and retrieve this object
// in binary format on the same system when that's helpful.

class snf_SMHDMY_Counter {                                                      // Sliding window "live" counter.
  private:

    bool do_input(int X, int& SUM, int* DATA, int& ORDINAL, int SIZE);          // Subroutine for assimilating input.

  public:
    snf_SMHDMY_Counter() {                                                      // When making a new one, reset all
        memset(this, 0, sizeof(snf_SMHDMY_Counter));                            // data to zero. It's all ints ;-)
    }

    // 60 seconds is a minute (6 x 10)

    int SEC6DATA[6], SEC6SUM, SEC6ORDINAL;
    int SEC10DATA[10], SEC10SUM, SEC10ORDINAL;

    // 60 minutes is an hour (6 x 10)

    int MIN6DATA[6], MIN6SUM, MIN6ORDINAL;
    int MIN10DATA[10], MIN10SUM, MIN10ORDINAL;

    // 24 hours is a day (4 x 6)

    int HOUR4DATA[4], HOUR4SUM, HOUR4ORDINAL;
    int HOUR6DATA[6], HOUR6SUM, HOUR6ORDINAL;

    // 7 days is a week (7)

    int WEEK7DATA[7], WEEK7SUM, WEEK7ORDINAL;

    // 30 days is a month (5 x 6)

    int MONTH5DATA[5], MONTH5SUM, MONTH5ORDINAL;
    int MONTH6DATA[6], MONTH6SUM, MONTH6ORDINAL;

    // 12 months (almost) is a year (3 x 4)

    int YEAR3DATA[3], YEAR3SUM, YEAR3ORDINAL;
    int YEAR4DATA[4], YEAR4SUM, YEAR4ORDINAL;

    // 365 days is a year

    int YEAR365DATA[365], YEAR365SUM, YEAR365ORDINAL;

    void input(int X);                                                          // Add new data to the counter.

    bool Cycled60Seconds() { return (0 == SEC6ORDINAL && 0 == SEC10ORDINAL); }  // Full cycle of data for seconds.
    int Sum60Seconds() { return SEC10SUM; }
    int Sum66Seconds() { return (SEC6SUM + SEC10SUM); }
    int SumThru1Minute() { return Sum66Seconds(); }                             // All samples thru one minute.

    bool Cycled60Minutes() {                                                    // Full cycle of data for minutes.
        return (Cycled60Seconds() && 0 == MIN6ORDINAL && 0 == MIN10ORDINAL);
    }

    int Sum60Minutes() { return MIN10SUM; }
    int Sum66Minutes() { return (MIN6SUM + MIN10SUM); }
    int SumThru1Hour() { return SumThru1Minute() + Sum66Minutes(); }            // All samples thru one hour.

    bool Cycled24Hours() {                                                      // Full cycle of data for hours.
        return (Cycled60Minutes() && 0 == HOUR4ORDINAL && 0 == HOUR6ORDINAL);
    }

    int Sum24Hours() { return HOUR6SUM; }
    int Sum28Hours() { return (HOUR4SUM + HOUR6SUM); }
    int SumThru1Day() { return SumThru1Hour() + Sum28Hours(); }                 // All samples thru one day.

    bool Cycled7Days() { return (Cycled24Hours() && 0 == WEEK7ORDINAL); }       // Full cycle of data for week.

    int Sum7Days() { return WEEK7SUM; }
    int SumThru1Week() { return SumThru1Day() + Sum7Days(); }                   // All samples thru one week.

    bool Cycled30Days() {                                                       // Full cycle of data for month.
        return (Cycled24Hours() && 0 == MONTH6ORDINAL && 0 == MONTH5ORDINAL);
    }

    int Sum30Days() { return MONTH6SUM; }
    int Sum35Days() { return (MONTH5SUM + MONTH6SUM); }
    int SumThru1Month() { return SumThru1Day() + Sum35Days(); }                  // All samples thu one month.

    bool Cycled12Months() {                                                     // Full cycle of data for 12 months.
        return (Cycled30Days() && 0 == YEAR3ORDINAL && 0 == YEAR4ORDINAL);
    }

    int Sum450Days() { return (YEAR3SUM + YEAR4SUM); }
    int SumThru1Year() { return SumThru1Month() + Sum450Days(); }               // All samples thru one year.

    bool Cycled365Days() { return (Cycled24Hours() && 0 == YEAR365ORDINAL); }   // Full cycle of data for 365 days.

    int Sum365Days() { return YEAR365SUM; }

};

//// snfLOGmgr /////////////////////////////////////////////////////////////////

// A note about the LOG manager and configuration data:
// Events that are logged with the log manager may come from scans using
// different configurations. In order to keep things as sane as possible,
// operations that are dependent on configuration information such as creating
// log file entries or producing status page data will require that an
// appropriate snfCFGData object be provided by reference and that the
// snfCFGData object be guaranteed to remain stable for the duration of the
// call. Changing snfCFGData may result in inconsistent results.
//
// This requirement is fairly easy to accomplish since posts to the LOGmgr
// will come from scanning engines that have a snfCFGPacket "grab()ed" during
// their operations, and executive requests will come from the ruelbase
// manager which can grab a snfCFGPacket for the duration of the request.

const int NumberOfResultCodes = 64;

class snfCounterPack {
  public:
    snfCounterPack();                                                           // Construct new CounterPacks clean.
    void reset();                                                               // How to reset a counter pack.

    Timer ActiveTime;                                                           // Measures Active (swapped in) Time.

    struct {

        unsigned long Scans;                                                    // Number of messages scanned.
        unsigned long Spam;                                                     // Count of spam results.
        unsigned long Ham;                                                      // Count of ham results.

        unsigned long GBUdbNormalTriggered;                                     // Count of indeterminate gbudb IP hits.

        unsigned long GBUdbWhiteTriggered;                                      // Count of GBUdb found source IP white.
        unsigned long GBUdbWhiteSymbolForced;                                   // Count of white was on and symbol was set.
        unsigned long GBUdbPatternSourceConflict;                               // Count of pattern was found with white IP.
        unsigned long GBUdbAutoPanicTriggered;                                  // Count of autopanic was triggered.
        unsigned long GBUdbAutoPanicExecuted;                                   // Count of an autopanic was added.

        unsigned long GBUdbBlackTriggered;                                      // Count of GBUdb found source IP black.
        unsigned long GBUdbBlackSymbolForced;                                   // Count of black was on and symbol was set.
        unsigned long GBUdbTruncateTriggered;                                   // Count of Truncate was possible.
        unsigned long GBUdbPeekTriggered;                                       // Count of we could peek.
        unsigned long GBUdbSampleTriggered;                                     // Count of we could sample.
        unsigned long GBUdbTruncateExecuted;                                    // Count of if we actually did truncate.
        unsigned long GBUdbPeekExecuted;                                        // Count of we peeked instead of truncating.
        unsigned long GBUdbSampleExecuted;                                      // Count of we sampled.

        unsigned long GBUdbCautionTriggered;                                    // Count of GBUdb found source IP suspicous.
        unsigned long GBUdbCautionSymbolForced;                                 // Count of caution was on and symbol was set.

        unsigned long PatternWasFound;                                          // Count of scanner matches.

        unsigned long RulePanicFound;                                           // Count of rule panics.

    } Events;
};

//// Interval timers precisely track the time between hack()s. There are
//// two timers inside. One is active, the other is stopped. Each time hack()
//// is called, one timer becomes active at the moment the other is stopped.

class IntervalTimer {                                                           // Precision interval timer.

  private:

    Timer A;                                                                    // Here is one timer.
    Timer B;                                                                    // Here is the other timer.
    bool ANotB;                                                                 // True if A is the active timer.

    Timer& Active();                                                            // Selects the active timer.
    Timer& Inactive();                                                          // Selects the inactive timer.

  public:

    msclock hack();                                                             // Chop off a new interval & return it.
    msclock Interval();                                                         // Return the last interval.
    msclock Elapsed();                                                          // Return the time since last hack.
};

//// PersistentState stores the counters we keep between runs.

class snfLOGPersistentState {
  public:

    snfLOGPersistentState() : Ready(0) {}

    bool Ready;                                                                 // True if we're ready to use.

    void store(string& FileNameToStore);                                        // Write the whole thing to a file.
    void restore(string& FileNameToRestore);                                    // Read the whole thing from a file.

    time_t LastSyncTime;                                                        // time_t of last Sync event.
    time_t LastSaveTime;                                                        // time_t of last GBUdb Save event.
    time_t LastCondenseTime;                                                    // time_t of last GBUdb Condense event.

    int LatestRuleID;                                                           // Latest rule ID seen so far.
    int SerialNumberCounter;                                                    // Remembers the serial number.
};

class snfLOGmgr : private Thread {

  private:

    Mutex MyMutex;                                                              // Mutex to serialize updates & queries.
    Mutex ConfigMutex;                                                          // Mutex to protect config changes.
    Mutex SerialNumberMutex;                                                    // Protects the serial number.
    Mutex PeekMutex;                                                            // Protects Peek Loop Counter.
    Mutex SampleMutex;                                                          // Protects Sample Loop Counter.
    Mutex StatusReportMutex;                                                    // Protects status report post & get.

    volatile int PeekEnableCounter;                                             // How many peek attempts recently?
    volatile int SampleEnableCounter;                                           // How many sample attempts recently?

    snfCounterPack CounterPackA, CounterPackB;                                  // Swapable counter packs.

    snfCounterPack* CurrentCounters;                                            // Current Event Counters.
    snfCounterPack* ReportingCounters;                                          // Counters being used to collect data.

    snfCounterPack* getSnapshot();                                              // Get a copy of the current counters.

    volatile bool Configured;                                                   // True if we're properly configured.
    volatile bool TimeToDie;                                                    // True when the thread should stop.

    void myTask();                                                              // Thread task.

    time_t StartupTime;                                                         // Time since engine started.

    snfLOGPersistentState Status;                                               // Persistent State Data.
    string PersistentFileName;                                                  // File name for the State Data.

    snfNETmgr* myNETmgr;                                                        // Net manager link.
    GBUdb* myGBUdb;                                                             // GBUdb link.

    // Configuration

    string ActiveRulebaseUTC;                                                   // UTC of last successful load.
    string AvailableRulebaseUTC;                                                // UTC of rulebase available for update.
    bool NewerRulebaseIsAvailable;                                              // True if a newer rulebase is available.

    string myPlatformVersion;                                                   // Version info for platform.

    bool Rotate_LocalTime;                                                      // Rotate logs using localtime.

    string LogsPath;                                                            // Path to logs directory.
    bool ClassicLogRotate;                                                      // True = Rotate Classic Log.
    bool XMLLogRotate;                                                          // True = Rotate XML Log.

    // Live stats

    snf_SMHDMY_Counter MessageCounter;
    snf_SMHDMY_Counter HamCounter;
    snf_SMHDMY_Counter SpamCounter;
    snf_SMHDMY_Counter WhiteCounter;
    snf_SMHDMY_Counter CautionCounter;
    snf_SMHDMY_Counter BlackCounter;
    snf_SMHDMY_Counter TruncateCounter;
    snf_SMHDMY_Counter SampleCounter;
    snf_SMHDMY_Counter AutoPanicCounter;
    snf_SMHDMY_Counter RulePanicCounter;
    snf_SMHDMY_Counter TimeCounter;

    // Histograms

    Histogram ResultsSecond;
    Histogram ResultsMinute;
    Histogram ResultsHour;
    Histogram RulesSecond;
    Histogram RulesMinute;
    Histogram RulesHour;
    Histogram PanicsSecond;
    Histogram PanicsMinute;
    Histogram PanicsHour;

    // Reporting

    string NodeId;                                                              // We need this for our status msgs.
    void do_StatusReports();                                                    // Update & sequence status reports.

    int XML_Log_Mode;                                                           // What is the XML log mode.
    int Classic_Log_Mode;                                                       // What is the Classic log mode.

    // Every second we get the basics and collect data. (local only)

    bool SecondReport_Log_OnOff;
    bool SecondReport_Append_OnOff;
    string SecondReport_Log_Filename;
    string SecondReportText;
    string SecondReportTimestamp;
    bool do_SecondReport();                                                     // Send our 1 second status report.

    // Every minute we get hard data and event logs. (for sync)

    bool MinuteReport_Log_OnOff;
    bool MinuteReport_Append_OnOff;
    string MinuteReport_Log_Filename;
    string MinuteReportText;
    string MinuteReportTimestamp;
    Histogram PatternRulesHistogram;
    bool do_MinuteReport();                                                     // Send our 1 minute status report.

    // Every hour we get a summary.

    bool HourReport_Log_OnOff;
    bool HourReport_Append_OnOff;
    string HourReport_Log_Filename;
    string HourReportText;
    string HourReportTimestamp;
    bool do_HourReport();                                                       // Send our 1 hour status report.

    void postStatusLog(                                                         // Post a Status log if required.
      const string& LogData,                                                    // Here's the log entry's data.
      const string& LogFileName,                                                // Here is where it should go.
      const bool LogEnabled,                                                    // This is true if we should write it.
      const bool AppendNotOverwrite,                                            // True=Append, False=Overwrite.
      DiscLogger& Logger                                                        // Lazy Log Writer to use.
    );

    DiscLogger SecondStatusLogger;                                              // Lazy writer for Second status.
    DiscLogger MinuteStatusLogger;                                              // Lazy writer for Minute status.
    DiscLogger HourStatusLogger;                                                // Lazy writer for Hour status.
    DiscLogger XMLScanLogger;                                                   // Lazy writer for XML Scan log.
    DiscLogger ClassicScanLogger;                                               // Lazy writer for Classic Scan log.

    void doXHDRs(snfCFGData& CFGData, snfScanData& ScanData);                   // XHDR sub routine for LogThisScan()
    void doXMLLogs(snfCFGData& CFGData, snfScanData& ScanData);                 // XML sub routine for LogThisScan()
    void doClassicLogs(snfCFGData& CFGData, snfScanData& ScanData);             // Classic sub routine for LogThisScan()

    void captureLTSMetrics(snfCFGData& CFGData, snfScanData& ScanData);         // LogThisScan section 1, Locked.
    void performLTSLogging(snfCFGData& CFGData, snfScanData& ScanData);         // LogThisScan section 2, Unlocked.

  public:

    snfLOGmgr();                                                                // Initialize & start the thread.
    ~snfLOGmgr();                                                               // Stop the thread & clean up.

    void stop();                                                                // Stops the manager.

    void linkNETmgr(snfNETmgr& N);                                              // Link in my NETmgr
    void linkGBUdb(GBUdb& G);                                                   // Link in my GBUdb

    void configure(snfCFGData& CFGData);                                        // Update the configuration.

    void updateActiveUTC(string ActiveUTC);                                     // Set active rulebase UTC.

    void logThisIPTest(IPTestRecord& I, string Action);                         // Capthre the data from an IP test.

    void logThisScan(snfCFGData& CFGData, snfScanData& ScanData);               // Capture the data from this scan.

    void logThisError(snfScanData& ScanData, const string ContextName,          // Inject an error log entry for this
      const int Code, const string Text                                         // scan using this number & message.
    );

    void logThisError(string ContextName, int Code, string Text);               // Log an error message.

    void logThisInfo(string ContextName, int Code, string text);                // Log an informational message.

    string PlatformVersion(string NewPlatformVersion);                          // Set platform version info.
    string PlatformVersion();                                                   // Get platform version info.

    string EngineVersion();                                                     // Get engine version info.

    void updateAvailableUTC(string& AvailableRulebaseTimestamp);                // Stores Available, true==update ready.
    string ActiveRulebaseTimestamp();                                           // Get active rulebase timestamp.
    string AvailableRulebaseTimestamp();                                        // Get available rulebase timestamp.
    bool isUpdateAvailable();                                                   // True if update is available.


    bool OkToPeek(int PeekOneInX);                                              // Check to see if it's ok to peek.
    bool OkToSample(int SampleOneInX);                                          // Check to see if it's ok to sample.

    time_t Timestamp();                                                         // Get an ordinary timestamp.
    string Timestamp(time_t t);                                                 // Convert time_t to a timestamp s.
    string& Timestamp(string& s);                                               // Appends a current timestamp in s.
    string LocalTimestamp(time_t t);                                            // Convert time_t to a local timestamp s.
    string& LocalTimestamp(string& s);                                          // Appends a current local timestamp in s.
    unsigned int SerialNumber();                                                // Returns the next serial number.
    string& SerialNumber(string& s);                                            // Appends the next serial number.

    void RecordSyncEvent();                                                     // Sets timestamp of latest Sync.
    int SecsSinceLastSync();                                                    // Gets seconds since latest Sync.
    void RecordSaveEvent();                                                     // Sets timestamp of latest Save.
    int SecsSinceLastSave();                                                    // Gets seconds since latest Save.
    void RecordCondenseEvent();                                                 // Sets timestamp of latest Condense.
    int SecsSinceLastCondense();                                                // Gets seconds since latest Condense.

    // Live stats functions

    double MessagesPerMinute();                                                 // Avg Msgs/Minute.
    double HamPerMinute();                                                      // Avg Ham/Minute.
    double SpamPerMinute();                                                     // Avg Spam/Minute.
    double WhitePerMinute();                                                    // Avg White/Minute.
    double CautionPerMinute();                                                  // Avg Caution/Minute.
    double BlackPerMinute();                                                    // Avg Black/Minute.
    double TruncatePerMinute();                                                 // Avg Truncate/Minute.
    double SamplePerMinute();                                                   // Avg Sample/Minute.
    int LatestRuleID();                                                         // Returns the latest Rule ID seen.

    int RunningTime();                                                          // Seconds running since startup.

    string getStatusSecondReport();                                             // Get latest status.second report.
    string getStatusMinuteReport();                                             // Get latest status.minute report.
    string getStatusHourReport();                                               // Get latest status.hour report.

    const static ThreadType Type;                                               // The thread's type.

};

#include "snfLOGmgr.inline.hpp"

#endif

//// End snfLOGmgr include only once
////////////////////////////////////////////////////////////////////////////////
