From c6d20dbfdfdca18fffea6b6c1e6ea9d8e324ae19 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Tue, 8 Mar 2011 21:43:52 -0800 Subject: [PATCH] Adding a few options to the ASCII writer. module LogAscii; export { # Output everything to stdout rather than into files. This is primarily # for testing purposes. const output_to_stdout = F &redef; # The separator between fields. const separator = "\t" &redef; # True to include a header line with column names. const include_header = T &redef; } --- TODO.logging | 7 +--- policy/bro.init | 1 + policy/logging-ascii.bro | 15 ++++++++ src/LogWriter.h | 4 +- src/LogWriterAscii.cc | 37 +++++++++++++------ src/LogWriterAscii.h | 5 +++ src/logging.bif | 11 +++++- .../Baseline/logging.ascii-options/output | 5 +++ testing/btest/logging/ascii-options.bro | 35 ++++++++++++++++++ 9 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 policy/logging-ascii.bro create mode 100644 testing/btest/Baseline/logging.ascii-options/output create mode 100644 testing/btest/logging/ascii-options.bro diff --git a/TODO.logging b/TODO.logging index 1aa9132a55..2e6c93b392 100644 --- a/TODO.logging +++ b/TODO.logging @@ -3,11 +3,8 @@ List of the things not implemented yet: - Not sure if the logging does the right thing with &optional and &default values. Needs testing. - Check the new event-value code. - - - Configure Ascii Writer: - - "redef LogAscii::output_to_stdout = T" - - "redef LogAscii::separator = '\t'" - - "redef LogAscii::headers = T" + - The Ascii writer doesn't escape the delimiter if it appears + within a field's value. Seems we need to do that. Notes about remote logging: diff --git a/policy/bro.init b/policy/bro.init index 84f0094a71..b3f78f0689 100644 --- a/policy/bro.init +++ b/policy/bro.init @@ -278,6 +278,7 @@ type entropy_test_result: record { @load bro.bif.bro @load logging # sic! Not logging.bif. +@load logging-ascii global bro_alarm_file: file &redef; global alarm_hook: function(msg: string): bool &redef; diff --git a/policy/logging-ascii.bro b/policy/logging-ascii.bro new file mode 100644 index 0000000000..0cabeae940 --- /dev/null +++ b/policy/logging-ascii.bro @@ -0,0 +1,15 @@ + +module LogAscii; + +export { + # Output everything to stdout rather than into files. This is primarily + # for testing purposes. + const output_to_stdout = F &redef; + + # The separator between fields. + const separator = "\t" &redef; + + # True to include a header line with column names. + const include_header = T &redef; +} + diff --git a/src/LogWriter.h b/src/LogWriter.h index 5a89e6be9e..3d3da905df 100644 --- a/src/LogWriter.h +++ b/src/LogWriter.h @@ -3,7 +3,9 @@ // // Note than classes derived from LogWriter must be fully thread-safe and not // use any non-safe Bro functionality (which is almost all ...). In -// particular, do not use fmt() but LogWriter::Fmt()!. +// particular, do not use fmt() but LogWriter::Fmt()!. The one exception is +// the constructor: that is guaranteed to be executed inside the main thread +// and it can thus access in particular global script variables. #ifndef LOGWRITER_H #define LOGWRITER_H diff --git a/src/LogWriterAscii.cc b/src/LogWriterAscii.cc index c38e49eb21..d5e550aa91 100644 --- a/src/LogWriterAscii.cc +++ b/src/LogWriterAscii.cc @@ -3,20 +3,30 @@ #include #include "LogWriterAscii.h" +#include "NetVar.h" LogWriterAscii::LogWriterAscii() { file = 0; + + output_to_stdout = BifConst::LogAscii::output_to_stdout; + include_header = BifConst::LogAscii::include_header; + separator = strdup(BifConst::LogAscii::separator->CheckString()); } LogWriterAscii::~LogWriterAscii() { if ( file ) fclose(file); + + free(separator); } bool LogWriterAscii::DoInit(string path, int num_fields, const LogField* const * fields) { + if ( output_to_stdout ) + path = "/dev/stdout"; + fname = IsSpecial(path) ? path : path + ".log"; if ( ! (file = fopen(fname.c_str(), "w")) ) @@ -25,22 +35,25 @@ bool LogWriterAscii::DoInit(string path, int num_fields, const LogField* const * return false; } - if ( fputs("# ", file) == EOF ) - goto write_error; - - for ( int i = 0; i < num_fields; i++ ) + if ( include_header ) { - const LogField* field = fields[i]; - if ( fputs(field->name.c_str(), file) == EOF ) + if ( fputs("# ", file) == EOF ) goto write_error; - if ( fputc('\t', file) == EOF ) + for ( int i = 0; i < num_fields; i++ ) + { + const LogField* field = fields[i]; + if ( fputs(field->name.c_str(), file) == EOF ) + goto write_error; + + if ( fputs(separator, file) == EOF ) + goto write_error; + } + + if ( fputc('\n', file) == EOF ) goto write_error; } - if ( fputc('\n', file) == EOF ) - goto write_error; - return true; write_error: @@ -65,7 +78,7 @@ bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields, Log for ( int i = 0; i < num_fields; i++ ) { if ( i > 0 ) - desc.Add("\t"); + desc.Add(separator); LogVal* val = vals[i]; const LogField* field = fields[i]; @@ -135,7 +148,7 @@ bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields, Log bool LogWriterAscii::DoRotate(string rotated_path, string postprocessor, double open, double close, bool terminating) { - if ( ! IsSpecial(Path()) ) + if ( IsSpecial(Path()) ) // Don't rotate special files. return true; diff --git a/src/LogWriterAscii.h b/src/LogWriterAscii.h index 0e060ea97e..0f42874da6 100644 --- a/src/LogWriterAscii.h +++ b/src/LogWriterAscii.h @@ -27,6 +27,11 @@ private: FILE* file; string fname; + + // Options from the script-level + bool output_to_stdout; + bool include_header; + char* separator; }; #endif diff --git a/src/logging.bif b/src/logging.bif index a4b56bb8d3..2095264910 100644 --- a/src/logging.bif +++ b/src/logging.bif @@ -11,7 +11,7 @@ type Stream: record; type RotationInfo: record; type RotationControl: record; -const Log::rotation_control : RotationControl; +const Log::rotation_control: RotationControl; function Log::__create_stream%(id: Log::ID, stream: Log::Stream%) : bool %{ @@ -60,3 +60,12 @@ function Log::__flush%(id: Log::ID%): bool bool result = log_mgr->Flush(id->AsEnumVal()); return new Val(result, TYPE_BOOL); %} + +# Options for the ASCII writer. + +module LogAscii; + +const output_to_stdout: bool; +const separator: string; +const include_header: bool; + diff --git a/testing/btest/Baseline/logging.ascii-options/output b/testing/btest/Baseline/logging.ascii-options/output new file mode 100644 index 0000000000..9a3e1f8d20 --- /dev/null +++ b/testing/btest/Baseline/logging.ascii-options/output @@ -0,0 +1,5 @@ +1299649281.43936|1.2.3.4|1234|2.3.4.5|80|success|unknown +1299649281.43936|1.2.3.4|1234|2.3.4.5|80|failure|US +1299649281.43936|1.2.3.4|1234|2.3.4.5|80|failure|UK +1299649281.43936|1.2.3.4|1234|2.3.4.5|80|success|BR +1299649281.43936|1.2.3.4|1234|2.3.4.5|80|failure|MX diff --git a/testing/btest/logging/ascii-options.bro b/testing/btest/logging/ascii-options.bro new file mode 100644 index 0000000000..747249342b --- /dev/null +++ b/testing/btest/logging/ascii-options.bro @@ -0,0 +1,35 @@ +# +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +redef LogAscii::output_to_stdout = T; +redef LogAscii::separator = "|"; +redef LogAscii::include_header = F; + +module SSH; + +export { + redef enum Log::ID += { SSH }; + + type Log: record { + t: time; + id: conn_id; # Will be rolled out into individual columns. + status: string &optional; + country: string &default="unknown"; + }; +} + +event bro_init() +{ + Log::create_stream(SSH, [$columns=Log]); + + local cid = [$orig_h=1.2.3.4, $orig_p=1234/tcp, $resp_h=2.3.4.5, $resp_p=80/tcp]; + + Log::write(SSH, [$t=network_time(), $id=cid, $status="success"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="US"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="UK"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="success", $country="BR"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="MX"]); + +} +