mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 16:48:19 +00:00
The ASCII writer now supports a filter config option
'only_single_header_row' that turns the output into CSV format. In that mode all meta data is skipped except for a single header line with the fields names. Example: local my_filter: Log::Filter = [$name = "my-filter", $writer = Log::WRITER_ASCII, $config = table(["only_single_header_row"] = "T")]; Contributed by Carsten Langer.
This commit is contained in:
parent
6c2ee1ef54
commit
a5e237f50c
7 changed files with 117 additions and 21 deletions
15
CHANGES
15
CHANGES
|
@ -1,4 +1,19 @@
|
||||||
|
|
||||||
|
2.1-178 | 2012-11-23 19:35:32 -0800
|
||||||
|
|
||||||
|
* The ASCII writer now supports a new filter config option
|
||||||
|
"only_single_header_row" that turns the output into CSV format
|
||||||
|
when set to "T". (Carsten Langer)
|
||||||
|
|
||||||
|
* Add new function flavor called a "hook". This new flavor of
|
||||||
|
function behaves like a "synchronous event". See
|
||||||
|
doc/scripts/builtins.rst more details on usage. (Jon Siwek)
|
||||||
|
|
||||||
|
* Improve auto-generated enum documentation. The names of enum types
|
||||||
|
are tracked so that variables holding a value of a given enum type
|
||||||
|
can generate a reference to it instead of just listing the type as
|
||||||
|
a generic "enum". (Jon Siwek)
|
||||||
|
|
||||||
2.1-171 | 2012-11-23 18:24:15 -0800
|
2.1-171 | 2012-11-23 18:24:15 -0800
|
||||||
|
|
||||||
* Fix ambiguity between composite table index and record ctor
|
* Fix ambiguity between composite table index and record ctor
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
2.1-171
|
2.1-178
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
##! Interface for the ASCII log writer. Redefinable options are available
|
##! Interface for the ASCII log writer. Redefinable options are available
|
||||||
##! to tweak the output format of ASCII logs.
|
##! to tweak the output format of ASCII logs.
|
||||||
|
##!
|
||||||
|
##! The ASCII writer supports currently one writer-specific filter option via
|
||||||
|
##! ``config``: setting ``only_single_header_row`` to ``T`` turns the output into
|
||||||
|
##! into CSV mode where only a single header row with the column names is printed
|
||||||
|
##! out as meta information. Example filter using this::
|
||||||
|
##!
|
||||||
|
##! local my_filter: Log::Filter = [$name = "my-filter", $writer = Log::WRITER_ASCII, $config = table(["only_single_header_row"] = "T")];
|
||||||
|
##!
|
||||||
|
|
||||||
module LogAscii;
|
module LogAscii;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ Ascii::Ascii(WriterFrontend* frontend) : WriterBackend(frontend)
|
||||||
{
|
{
|
||||||
fd = 0;
|
fd = 0;
|
||||||
ascii_done = false;
|
ascii_done = false;
|
||||||
|
only_single_header_row = false;
|
||||||
|
|
||||||
output_to_stdout = BifConst::LogAscii::output_to_stdout;
|
output_to_stdout = BifConst::LogAscii::output_to_stdout;
|
||||||
include_meta = BifConst::LogAscii::include_meta;
|
include_meta = BifConst::LogAscii::include_meta;
|
||||||
|
@ -80,7 +81,7 @@ void Ascii::CloseFile(double t)
|
||||||
if ( ! fd )
|
if ( ! fd )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( include_meta )
|
if ( include_meta && ! only_single_header_row )
|
||||||
WriteHeaderField("close", Timestamp(0));
|
WriteHeaderField("close", Timestamp(0));
|
||||||
|
|
||||||
safe_close(fd);
|
safe_close(fd);
|
||||||
|
@ -108,29 +109,29 @@ bool Ascii::DoInit(const WriterInfo& info, int num_fields, const Field* const *
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ( WriterInfo::config_map::const_iterator i = info.config.begin(); i != info.config.end(); i++ )
|
||||||
|
{
|
||||||
|
if ( strcmp(i->first, "only_single_header_row") == 0 )
|
||||||
|
{
|
||||||
|
if ( strcmp(i->second, "T") == 0 )
|
||||||
|
only_single_header_row = true;
|
||||||
|
|
||||||
|
else if ( strcmp(i->second, "F") == 0 )
|
||||||
|
only_single_header_row = false;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error("invalid value for 'only_single_header_row', must be boolean (T/F)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( include_meta )
|
if ( include_meta )
|
||||||
{
|
{
|
||||||
string names;
|
string names;
|
||||||
string types;
|
string types;
|
||||||
|
|
||||||
string str = string(meta_prefix, meta_prefix_len)
|
|
||||||
+ "separator " // Always use space as separator here.
|
|
||||||
+ get_escaped_string(string(separator, separator_len), false)
|
|
||||||
+ "\n";
|
|
||||||
|
|
||||||
if ( ! safe_write(fd, str.c_str(), str.length()) )
|
|
||||||
goto write_error;
|
|
||||||
|
|
||||||
if ( ! (WriteHeaderField("set_separator", get_escaped_string(
|
|
||||||
string(set_separator, set_separator_len), false)) &&
|
|
||||||
WriteHeaderField("empty_field", get_escaped_string(
|
|
||||||
string(empty_field, empty_field_len), false)) &&
|
|
||||||
WriteHeaderField("unset_field", get_escaped_string(
|
|
||||||
string(unset_field, unset_field_len), false)) &&
|
|
||||||
WriteHeaderField("path", get_escaped_string(path, false)) &&
|
|
||||||
WriteHeaderField("open", Timestamp(0))) )
|
|
||||||
goto write_error;
|
|
||||||
|
|
||||||
for ( int i = 0; i < num_fields; ++i )
|
for ( int i = 0; i < num_fields; ++i )
|
||||||
{
|
{
|
||||||
if ( i > 0 )
|
if ( i > 0 )
|
||||||
|
@ -143,11 +144,39 @@ bool Ascii::DoInit(const WriterInfo& info, int num_fields, const Field* const *
|
||||||
types += fields[i]->TypeName().c_str();
|
types += fields[i]->TypeName().c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( only_single_header_row )
|
||||||
|
{
|
||||||
|
// A single CSV-style line is all we need.
|
||||||
|
string str = names + "\n";
|
||||||
|
if ( ! safe_write(fd, str.c_str(), str.length()) )
|
||||||
|
goto write_error;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string str = string(meta_prefix, meta_prefix_len)
|
||||||
|
+ "separator " // Always use space as separator here.
|
||||||
|
+ get_escaped_string(string(separator, separator_len), false)
|
||||||
|
+ "\n";
|
||||||
|
|
||||||
|
if ( ! safe_write(fd, str.c_str(), str.length()) )
|
||||||
|
goto write_error;
|
||||||
|
|
||||||
|
if ( ! (WriteHeaderField("set_separator", get_escaped_string(
|
||||||
|
string(set_separator, set_separator_len), false)) &&
|
||||||
|
WriteHeaderField("empty_field", get_escaped_string(
|
||||||
|
string(empty_field, empty_field_len), false)) &&
|
||||||
|
WriteHeaderField("unset_field", get_escaped_string(
|
||||||
|
string(unset_field, unset_field_len), false)) &&
|
||||||
|
WriteHeaderField("path", get_escaped_string(path, false)) &&
|
||||||
|
WriteHeaderField("open", Timestamp(0))) )
|
||||||
|
goto write_error;
|
||||||
|
|
||||||
if ( ! (WriteHeaderField("fields", names)
|
if ( ! (WriteHeaderField("fields", names)
|
||||||
&& WriteHeaderField("types", types)) )
|
&& WriteHeaderField("types", types)) )
|
||||||
goto write_error;
|
goto write_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
write_error:
|
write_error:
|
||||||
|
|
|
@ -45,6 +45,7 @@ private:
|
||||||
// Options set from the script-level.
|
// Options set from the script-level.
|
||||||
bool output_to_stdout;
|
bool output_to_stdout;
|
||||||
bool include_meta;
|
bool include_meta;
|
||||||
|
bool only_single_header_row;
|
||||||
|
|
||||||
char* separator;
|
char* separator;
|
||||||
int separator_len;
|
int separator_len;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
t id.orig_h id.orig_p id.resp_h id.resp_p status country b
|
||||||
|
1353727995.082217 1.2.3.4 1234 2.3.4.5 80 success unknown -
|
||||||
|
1353727995.082217 1.2.3.4 1234 2.3.4.5 80 - US -
|
||||||
|
1353727995.082217 1.2.3.4 1234 2.3.4.5 80 failure UK -
|
||||||
|
1353727995.082217 1.2.3.4 1234 2.3.4.5 80 - BR -
|
||||||
|
1353727995.082217 1.2.3.4 1234 2.3.4.5 80 failure (empty) T
|
37
testing/btest/scripts/base/frameworks/logging/ascii-csv.bro
Normal file
37
testing/btest/scripts/base/frameworks/logging/ascii-csv.bro
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: bro -b %INPUT
|
||||||
|
# @TEST-EXEC: cat ssh.log | grep -v PREFIX.*20..- >ssh-filtered.log
|
||||||
|
# @TEST-EXEC: btest-diff ssh-filtered.log
|
||||||
|
|
||||||
|
module SSH;
|
||||||
|
|
||||||
|
export {
|
||||||
|
redef enum Log::ID += { LOG };
|
||||||
|
|
||||||
|
type Log: record {
|
||||||
|
t: time;
|
||||||
|
id: conn_id; # Will be rolled out into individual columns.
|
||||||
|
status: string &optional;
|
||||||
|
country: string &default="unknown";
|
||||||
|
b: bool &optional;
|
||||||
|
} &log;
|
||||||
|
}
|
||||||
|
|
||||||
|
event bro_init()
|
||||||
|
{
|
||||||
|
Log::create_stream(SSH::LOG, [$columns=Log]);
|
||||||
|
|
||||||
|
local filter = Log::get_filter(SSH::LOG, "default");
|
||||||
|
filter$config = table(["only_single_header_row"] = "T");
|
||||||
|
Log::add_filter(SSH::LOG, filter);
|
||||||
|
|
||||||
|
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::LOG, [$t=network_time(), $id=cid, $status="success"]);
|
||||||
|
Log::write(SSH::LOG, [$t=network_time(), $id=cid, $country="US"]);
|
||||||
|
Log::write(SSH::LOG, [$t=network_time(), $id=cid, $status="failure", $country="UK"]);
|
||||||
|
Log::write(SSH::LOG, [$t=network_time(), $id=cid, $country="BR"]);
|
||||||
|
Log::write(SSH::LOG, [$t=network_time(), $id=cid, $b=T, $status="failure", $country=""]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue