diff --git a/TODO.logging b/TODO.logging index d5bb3744b7..3e612eab5a 100644 --- a/TODO.logging +++ b/TODO.logging @@ -1,9 +1,25 @@ List of the things not implemented yet: - - Cluster-style remote_print. - - Rotation support. - Not sure if the logging does the right thing with &optional and &default values. Needs testing. - Spawning writers in separate threads (not clear if we want that initially). - - Check the new event-value code. + - Check the new event-value code. + - Configure Ascii Writer: + - "redef LogAscii::output_to_stdout = T" + - "redef LogAscii::separator = '\t'" + - "redef LogAscii::headers = T" + + - Extended filter manipualtion interface on the script level: + - Disalbe stream altogether. + - Change individual options of an existing filter. + +Notes about remote logging: + + - The receiver must create the stream locally via + Log::create_stream() in order to receive data for it. If not + created, anything sent will be ignored. + + - However, the receiver does not need to create filter locally. + Filter processing is done and the sender side, and as long as + stream exists at the receiver, it will record whatever it gets. diff --git a/policy/logging.bro b/policy/logging.bro index f3d4e35c37..90f42a8874 100644 --- a/policy/logging.bro +++ b/policy/logging.bro @@ -3,13 +3,6 @@ module Log; # Log::ID and Log::Writer are defined in bro.init due to circular dependencies. export { - # Information passed to a rotation callback function. - type RotationInfo: record { - path: string; # Original path value. - open: time; # Time when opened. - close: time; # Time when closed. - }; - # If true, local logging is by default enabled for all filters. const enable_local_logging = T &redef; @@ -19,20 +12,6 @@ export { # The default writer to use. const default_writer = Log::WRITER_ASCII &redef; - # Default rotation interval; zero disables rotation. - const default_rotation_interval = 0secs &redef; - - # Default naming suffix format. - const default_rotation_date_format = "%y-%m-%d_%H.%M.%S" &redef; - - # Default postprocessor for writers outputting into files. - const default_rotation_postprocessor = "" &redef; - - # Default function to construct the name of the rotated file. - # The default implementation includes - # default_rotation_date_format into the file name. - global default_rotation_path_func: function(info: RotationInfo) : string &redef; - # A stream defining the logging. type Stream: record { # A record type defining the log's columns. @@ -81,6 +60,39 @@ export { writer: Writer &default=Log::default_writer; }; + ### Log rotation support. + + # Information passed to a rotation callback function. + type RotationInfo: record { + writer: Writer; # The writer. + path: string; # Original path value. + open: time; # Time when opened. + close: time; # Time when closed. + }; + + # Default rotation interval; zero disables rotation. + const default_rotation_interval = 0secs &redef; + + # Default naming suffix format. + const default_rotation_date_format = "%y-%m-%d_%H.%M.%S" &redef; + + # Default postprocessor for writers outputting into files. + const default_rotation_postprocessor = "" &redef; + + # Default function to construct the name of the rotated file. + # The default implementation includes + # default_rotation_date_format into the file name. + global default_rotation_path_func: function(info: RotationInfo) : string &redef; + + type RotationControl: record { + interv: interval &default=default_rotation_interval; + date_fmt: string &default=default_rotation_date_format; + postprocessor: string &default=default_rotation_postprocessor; + }; + + # Defines rotation parameters per (id, path) tuple. + const rotation_control: table[Writer, string] of Log::RotationControl &default=[] &redef; + global create_stream: function(id: Log::ID, stream: Log::Stream) : bool; global add_filter: function(id: Log::ID, filter: Log::Filter) : bool; global remove_filter: function(id: Log::ID, name: string) : bool; @@ -97,7 +109,8 @@ module Log; function default_rotation_path_func(info: RotationInfo) : string { - return fmt("%s-%s", info$path, strftime(default_rotation_date_format, info$open)); + local date_fmt = rotation_control[info$writer, info$path]$date_fmt; + return fmt("%s-%s", info$path, strftime(date_fmt, info$open)); } function create_stream(id: Log::ID, stream: Log::Stream) : bool diff --git a/src/LogMgr.cc b/src/LogMgr.cc index 46293e71fe..8f44c4a520 100644 --- a/src/LogMgr.cc +++ b/src/LogMgr.cc @@ -40,9 +40,10 @@ struct LogMgr::Filter { }; struct LogMgr::WriterInfo { - double open_time; - Timer* rotation_timer; - LogWriter *writer; + EnumVal* type; + double open_time; + Timer* rotation_timer; + LogWriter *writer; }; struct LogMgr::Stream { @@ -229,6 +230,7 @@ LogMgr::Stream::~Stream() if ( winfo->rotation_timer ) timer_mgr->Cancel(winfo->rotation_timer); + Unref(winfo->type); delete winfo->writer; delete i->second; } @@ -798,6 +800,7 @@ LogWriter* LogMgr::CreateWriter(EnumVal* id, EnumVal* writer, string path, int n } WriterInfo* winfo = new WriterInfo; + winfo->type = writer->Ref()->AsEnumVal(); winfo->writer = writer_obj; winfo->open_time = network_time; winfo->rotation_timer = 0; @@ -928,6 +931,22 @@ void RotationTimer::Dispatch(double t, int is_expire) } } +RecordVal* LogMgr::LookupRotationControl(EnumVal* writer, string path) + { + TableVal* rc = BifConst::Log::rotation_control->AsTableVal(); + + ListVal* index = new ListVal(TYPE_ANY); + index->Append(writer->Ref()); + index->Append(new StringVal(path.c_str())); + + Val* r = rc->Lookup(index); + assert(r); + + Unref(index); + + return r->AsRecordVal(); + } + void LogMgr::InstallRotationTimer(WriterInfo* winfo) { if ( terminating ) @@ -939,7 +958,10 @@ void LogMgr::InstallRotationTimer(WriterInfo* winfo) winfo->rotation_timer = 0; } - double rotation_interval = BifConst::Log::default_rotation_interval; + RecordVal* rc = LookupRotationControl(winfo->type, winfo->writer->Path()); + + int idx = rc->Type()->AsRecordType()->FieldOffset("interv"); + double rotation_interval = rc->LookupWithDefault(idx)->AsInterval(); if ( rotation_interval ) { @@ -974,14 +996,19 @@ void LogMgr::Rotate(WriterInfo* winfo) // Create the RotationInfo record. RecordVal* info = new RecordVal(BifType::Record::Log::RotationInfo); - info->Assign(0, new StringVal(winfo->writer->Path().c_str())); - info->Assign(1, new Val(winfo->open_time, TYPE_TIME)); - info->Assign(2, new Val(network_time, TYPE_TIME)); + info->Assign(0, winfo->type->Ref()); + info->Assign(1, new StringVal(winfo->writer->Path().c_str())); + info->Assign(2, new Val(winfo->open_time, TYPE_TIME)); + info->Assign(3, new Val(network_time, TYPE_TIME)); // Call the function building us the new path. Func* rotation_path_func = internal_func("Log::default_rotation_path_func"); - string rotation_postprocessor = BifConst::Log::default_rotation_postprocessor->AsString()->CheckString(); + + RecordVal* rc = LookupRotationControl(winfo->type, winfo->writer->Path()); + + int idx = rc->Type()->AsRecordType()->FieldOffset("postprocessor"); + string rotation_postprocessor = rc->LookupWithDefault(idx)->AsString()->CheckString(); val_list vl(1); vl.append(info); diff --git a/src/LogMgr.h b/src/LogMgr.h index 1188b80336..6a0c16159f 100644 --- a/src/LogMgr.h +++ b/src/LogMgr.h @@ -99,6 +99,7 @@ private: void RemoveDisabledWriters(Stream* stream); void InstallRotationTimer(WriterInfo* winfo); void Rotate(WriterInfo* info); + RecordVal* LookupRotationControl(EnumVal* writer, string path); vector streams; // Indexed by stream enum. }; diff --git a/src/logging.bif b/src/logging.bif index a561c6c5a3..0babf75a06 100644 --- a/src/logging.bif +++ b/src/logging.bif @@ -9,9 +9,9 @@ module Log; type Filter: record; type Stream: record; type RotationInfo: record; +type RotationControl: record; -const Log::default_rotation_interval: interval; -const Log::default_rotation_postprocessor: string; +const Log::rotation_control : RotationControl; function Log::__create_stream%(id: Log::ID, stream: Log::Stream%) : bool %{