Threaded logging framework.

This is based on Gilbert's code but I ended up refactoring it quite a
bit. That's why I didn't do a direct merge but started with a new
branch and copied things over to adapt. It looks quite a bit different
now as I tried to generalize things a bit more to also support the
Input Framework.

The larger changes code are:

    - Moved all logging code into subdirectory src/logging/. Code
      here is in namespace "logging".

    - Moved all threading code into subdirectory src/threading/. Code
      here is in namespace "threading".

    - Introduced a central thread manager that tracks threads and is
      in charge of termination and (eventually) statistics.

    - Refactored logging independent threading code into base classes
      BasicThread and MsgThread. The former encapsulates all the
      pthread code with simple start/stop methods and provides a
      single Run() method to override.

      The latter is derived from BasicThread and adds bi-directional
      message passing between main and child threads. The hope is that
      the Input Framework can reuse this part quite directly.

    - A log writer is now split into a general WriterFrontend
      (LogEmissary in Gilbert's code) and a type-specific
      WriterBackend. Specific writers are implemented by deriving from
      the latter. (The plugin interface is almost unchanged compared
      to the 2.0 version.).

      Frontend and backend communicate via MsgThread's message
      passing.

    - MsgThread (and thus WriterBackend) has a Heartbeat() method that
      a thread can override to execute code on a regular basis. It's
      triggered roughly once a second by the main thread.

    - Integration into "the rest of Bro". Threads can send messages to
      the reporter and do debugging output; they are hooked into the
      I/O loop for sending messages back; and there's a new debugging
      stream "threading" that logs, well, threading activity.

This all seems to work for the most part, but it's not done yet.

TODO list:

    - Not all tests pass yet. In particular, diffs for the external
      tests seem to indicate some memory problem (no crashes, just an
      occasional weird character).

    - Only tested in --enable-debug mode.

    - Only tested on Linux.

    - Needs leak check.

    - Each log write is currently a single inter-thread message. Bring
      Gilbert's bulk writes back.

    - Code needs further cleanup.

    - Document the class API.

    - Document the internal structure of the logging framework.

    - Check for robustness: live traffic, aborting, signals, etc.

    - Add thread statistics to profile.log (most of the code is there).

    - Customize the OS-visible thread names on platforms that support it.
This commit is contained in:
Robin Sommer 2012-01-26 17:47:36 -08:00
parent 60ae6f01d1
commit e4e770d475
28 changed files with 1745 additions and 503 deletions

View file

@ -29,7 +29,6 @@ extern "C" void OPENSSL_add_all_algorithms_conf(void);
#include "Event.h"
#include "File.h"
#include "Reporter.h"
#include "LogMgr.h"
#include "Net.h"
#include "NetVar.h"
#include "Var.h"
@ -48,7 +47,10 @@ extern "C" void OPENSSL_add_all_algorithms_conf(void);
#include "DPM.h"
#include "BroDoc.h"
#include "Brofiler.h"
#include "LogWriterAscii.h"
#include "threading/Manager.h"
#include "logging/Manager.h"
#include "logging/writers/Ascii.h"
#include "binpac_bro.h"
@ -75,7 +77,8 @@ char* writefile = 0;
name_list prefixes;
DNS_Mgr* dns_mgr;
TimerMgr* timer_mgr;
LogMgr* log_mgr;
logging::Manager* log_mgr = 0;
threading::Manager* thread_mgr = 0;
Stmt* stmts;
EventHandlerPtr net_done = 0;
RuleMatcher* rule_matcher = 0;
@ -197,7 +200,7 @@ void usage()
fprintf(stderr, " $BRO_PREFIXES | prefix list (%s)\n", bro_prefixes());
fprintf(stderr, " $BRO_DNS_FAKE | disable DNS lookups (%s)\n", bro_dns_fake());
fprintf(stderr, " $BRO_SEED_FILE | file to load seeds from (not set)\n");
fprintf(stderr, " $BRO_LOG_SUFFIX | ASCII log file extension (.%s)\n", LogWriterAscii::LogExt().c_str());
fprintf(stderr, " $BRO_LOG_SUFFIX | ASCII log file extension (.%s)\n", logging::writer::Ascii::LogExt().c_str());
fprintf(stderr, " $BRO_PROFILER_FILE | Output file for script execution statistics (not set)\n");
exit(1);
@ -287,6 +290,8 @@ void terminate_bro()
if ( remote_serializer )
remote_serializer->LogStats();
thread_mgr->Terminate();
delete timer_mgr;
delete dns_mgr;
delete persistence_serializer;
@ -299,6 +304,7 @@ void terminate_bro()
delete remote_serializer;
delete dpm;
delete log_mgr;
delete thread_mgr;
delete reporter;
}
@ -661,7 +667,9 @@ int main(int argc, char** argv)
set_processing_status("INITIALIZING", "main");
bro_start_time = current_time(true);
reporter = new Reporter();
thread_mgr = new threading::Manager();
#ifdef DEBUG
if ( debug_streams )
@ -727,7 +735,7 @@ int main(int argc, char** argv)
persistence_serializer = new PersistenceSerializer();
remote_serializer = new RemoteSerializer();
event_registry = new EventRegistry();
log_mgr = new LogMgr();
log_mgr = new logging::Manager();
if ( events_file )
event_player = new EventPlayer(events_file);
@ -1001,6 +1009,8 @@ int main(int argc, char** argv)
have_pending_timers = ! reading_traces && timer_mgr->Size() > 0;
io_sources.Register(thread_mgr, true);
if ( io_sources.Size() > 0 || have_pending_timers )
{
if ( profiling_logger )