zeek/scripts/policy/misc/stats.zeek
Benjamin Bannier d5fd29edcd Prefer explicit construction to coercion in record initialization
While we support initializing records via coercion from an expression
list, e.g.,

    local x: X = [$x1=1, $x2=2];

this can sometimes obscure the code to readers, e.g., when assigning to
value declared and typed elsewhere. The language runtime has a similar
overhead since instead of just constructing a known type it needs to
check at runtime that the coercion from the expression list is valid;
this can be slower than just writing the readible code in the first
place, see #4559.

With this patch we use explicit construction, e.g.,

    local x = X($x1=1, $x2=2);
2025-07-11 16:28:37 -07:00

240 lines
8.3 KiB
Text

##! Log memory/packet/lag statistics.
@load base/frameworks/notice
@load base/frameworks/telemetry
@load base/utils/time
module Stats;
export {
redef enum Log::ID += { LOG };
global log_policy: Log::PolicyHook;
## How often stats are reported.
option report_interval = 5min;
type Info: record {
## Timestamp for the measurement.
ts: time &log;
## Peer that generated this log. Mostly for clusters.
peer: string &log;
## Amount of memory currently in use in MB.
mem: count &log;
## Number of packets processed since the last stats interval.
pkts_proc: count &log;
## Number of bytes received since the last stats interval if
## reading live traffic.
bytes_recv: count &log;
## Number of packets dropped since the last stats interval if
## reading live traffic.
pkts_dropped: count &log &optional;
## Number of packets seen on the link since the last stats
## interval if reading live traffic.
pkts_link: count &log &optional;
## Lag between the wall clock and packet timestamps if reading
## live traffic.
pkt_lag: interval &log &optional;
## Number of packets filtered from the link since the last
## stats interval if reading live traffic.
pkts_filtered: count &log &optional;
## Number of events processed since the last stats interval.
events_proc: count &log;
## Number of events that have been queued since the last stats
## interval.
events_queued: count &log;
## TCP connections currently in memory.
active_tcp_conns: count &log;
## UDP connections currently in memory.
active_udp_conns: count &log;
## ICMP connections currently in memory.
active_icmp_conns: count &log;
## TCP connections seen since last stats interval.
tcp_conns: count &log;
## UDP connections seen since last stats interval.
udp_conns: count &log;
## ICMP connections seen since last stats interval.
icmp_conns: count &log;
## Number of timers scheduled since last stats interval.
timers: count &log;
## Current number of scheduled timers.
active_timers: count &log;
## Number of files seen since last stats interval.
files: count &log;
## Current number of files actively being seen.
active_files: count &log;
## Number of DNS requests seen since last stats interval.
dns_requests: count &log;
## Current number of DNS requests awaiting a reply.
active_dns_requests: count &log;
## Current size of TCP data in reassembly.
reassem_tcp_size: count &log;
## Current size of File data in reassembly.
reassem_file_size: count &log;
## Current size of packet fragment data in reassembly.
reassem_frag_size: count &log;
## Current size of unknown data in reassembly (this is only PIA buffer right now).
reassem_unknown_size: count &log;
};
## Event to catch stats as they are written to the logging stream.
global log_stats: event(rec: Info);
}
global bytes_received_cf = Telemetry::register_counter_family(Telemetry::MetricOpts(
$prefix="zeek",
$name="net-received-bytes",
$unit="",
$help_text="Total number of bytes received",
));
global packets_received_cf = Telemetry::register_counter_family(Telemetry::MetricOpts(
$prefix="zeek",
$name="net-received-packets",
$unit="",
$help_text="Total number of packets received",
));
global packets_dropped_cf = Telemetry::register_counter_family(Telemetry::MetricOpts(
$prefix="zeek",
$name="net-dropped-packets",
$unit="",
$help_text="Total number of packets dropped",
));
global link_packets_cf = Telemetry::register_counter_family(Telemetry::MetricOpts(
$prefix="zeek",
$name="net-link-packets",
$unit="",
$help_text="Total number of packets on the packet source link before filtering",
));
global packets_filtered_cf = Telemetry::register_counter_family(Telemetry::MetricOpts(
$prefix="zeek",
$name="net-filtered-packets",
$unit="",
$help_text="Total number of packets filtered",
));
global packet_lag_gf = Telemetry::register_gauge_family(Telemetry::MetricOpts(
$prefix="zeek",
$name="net-packet-lag",
$unit="seconds",
$help_text="Difference of network time and wallclock time in seconds.",
));
# Gauge as motivated by:
# https://www.robustperception.io/are-increasing-timestamps-counters-or-gauges/
global network_time_cf = Telemetry::register_gauge_family(Telemetry::MetricOpts(
$prefix="zeek",
$name="net-timestamp",
$unit="seconds",
$help_text="The current network time.",
));
global no_labels: vector of string;
hook Telemetry::sync()
{
Telemetry::gauge_family_set(network_time_cf, no_labels, time_to_double(network_time()));
local net_stats = get_net_stats();
Telemetry::counter_family_set(bytes_received_cf, no_labels, net_stats$bytes_recvd);
Telemetry::counter_family_set(packets_received_cf, no_labels, net_stats$pkts_recvd);
if ( reading_live_traffic() )
{
Telemetry::counter_family_set(packets_dropped_cf, no_labels, net_stats$pkts_dropped);
Telemetry::counter_family_set(link_packets_cf, no_labels, net_stats$pkts_link);
if ( net_stats?$pkts_filtered )
Telemetry::counter_family_set(packets_filtered_cf, no_labels, net_stats$pkts_filtered);
Telemetry::gauge_family_set(packet_lag_gf, no_labels,
interval_to_double(current_time() - network_time()));
}
}
event zeek_init() &priority=5
{
Log::create_stream(Stats::LOG, Log::Stream($columns=Info, $ev=log_stats, $path="stats", $policy=log_policy));
}
event check_stats(then: time, last_ns: NetStats, last_cs: ConnStats, last_ps: ProcStats, last_es: EventStats, last_rs: ReassemblerStats, last_ts: TimerStats, last_fs: FileAnalysisStats, last_ds: DNSStats)
{
local nettime = network_time();
local ns = get_net_stats();
local cs = get_conn_stats();
local ps = get_proc_stats();
local es = get_event_stats();
local rs = get_reassembler_stats();
local ts = get_timer_stats();
local fs = get_file_analysis_stats();
local ds = get_dns_stats();
local info = Info($ts=nettime,
$peer=peer_description,
$mem=ps$mem/1048576,
$pkts_proc=ns$pkts_recvd - last_ns$pkts_recvd,
$bytes_recv = ns$bytes_recvd - last_ns$bytes_recvd,
$active_tcp_conns=cs$num_tcp_conns,
$tcp_conns=cs$cumulative_tcp_conns - last_cs$cumulative_tcp_conns,
$active_udp_conns=cs$num_udp_conns,
$udp_conns=cs$cumulative_udp_conns - last_cs$cumulative_udp_conns,
$active_icmp_conns=cs$num_icmp_conns,
$icmp_conns=cs$cumulative_icmp_conns - last_cs$cumulative_icmp_conns,
$reassem_tcp_size=rs$tcp_size,
$reassem_file_size=rs$file_size,
$reassem_frag_size=rs$frag_size,
$reassem_unknown_size=rs$unknown_size,
$events_proc=es$dispatched - last_es$dispatched,
$events_queued=es$queued - last_es$queued,
$timers=ts$cumulative - last_ts$cumulative,
$active_timers=ts$current,
$files=fs$cumulative - last_fs$cumulative,
$active_files=fs$current,
$dns_requests=ds$requests - last_ds$requests,
$active_dns_requests=ds$pending);
# Someone's going to have to explain what this is and add a field to the Info record.
# info$util = 100.0*((ps$user_time + ps$system_time) - (last_ps$user_time + last_ps$system_time))/(now-then);
if ( reading_live_traffic() )
{
info$pkt_lag = get_packet_lag();
info$pkts_dropped = ns$pkts_dropped - last_ns$pkts_dropped;
info$pkts_link = ns$pkts_link - last_ns$pkts_link;
# This makes the assumption that if pkts_filtered is valid, it's been valid in
# all of the previous calls.
if ( ns?$pkts_filtered )
info$pkts_filtered = ns$pkts_filtered - last_ns$pkts_filtered;
}
Log::write(Stats::LOG, info);
if ( zeek_is_terminating() )
# No more stats will be written or scheduled when Zeek is
# shutting down.
return;
schedule report_interval { check_stats(nettime, ns, cs, ps, es, rs, ts, fs, ds) };
}
event zeek_init()
{
schedule report_interval { check_stats(network_time(), get_net_stats(), get_conn_stats(), get_proc_stats(), get_event_stats(), get_reassembler_stats(), get_timer_stats(), get_file_analysis_stats(), get_dns_stats()) };
}