What each client prefix has been doing over the last minute.
track/2 runs for every request Limen sees (including requests that take
the pass cookie fast path, and routes in :track mode) and counts, per
prefix, in the sliding minute window of Limen.State.Window:
- requests;
- pages (navigations) and assets (scripts, styles, images, fonts);
- distinct paths, deduplicated with a rotating Bloom filter
(
Limen.Sketch.RotatingBloom); 404 Not Foundresponses, counted when the response is sent.
The counts share one row per prefix (see key/1), so counting a request
costs one table update, and reading the counts back costs nothing. On a
prefix's first request of each minute, it also adds the prefix to the
HyperLogLog behind Limen.State.active_prefixes/1, and counts it as a
client of the request's JA4 fingerprint, for dashboards.
collect/1 turns the counts into signals. Scrapers tend to fetch many
pages and few assets, and to probe paths that do not exist; browsers load
a page's assets (unless they are cached, which makes a low asset ratio a
weak signal on its own).
Provides :requests_per_minute, :pages_per_minute, :assets_per_minute,
:asset_ratio (assets per page, nil before any page), :not_found_ratio
(404s per request), :distinct_paths_per_minute (a path revisited within
two minutes is not counted again) and :active_prefixes (distinct client
prefixes the instance saw on this node over the last one to two minutes; a
sudden jump suggests a distributed flood).
Summary
Functions
The window key of a prefix's counts.
Classifies a request as a :page navigation, an :asset or :other.
Counts the request and arranges for a 404 response to be counted.
Functions
The window key of a prefix's counts.
They share one row of the minute window, so that counting a request costs
one table update: requests, pages, assets, 404 responses and new paths,
in that order.
@spec kind(Limen.Context.t()) :: :page | :asset | :other
Classifies a request as a :page navigation, an :asset or :other.
Uses sec-fetch-dest
(read into the context by Limen.Signal.identify/2) when the client sends
it, and the path extension otherwise.
@spec track(Plug.Conn.t(), Limen.Context.t()) :: {Plug.Conn.t(), Limen.Context.t()}
Counts the request and arranges for a 404 response to be counted.