Limen.Signal.Behaviour (limen v0.2.1)

Copy Markdown View Source

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 Found responses, 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

key(prefix)

@spec key(term()) :: {:limen_behaviour, term()}

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.

kind(ctx)

@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.

track(conn, ctx)

Counts the request and arranges for a 404 response to be counted.