Add logtail if=$variable filtering and update log format examples

- ipng_stats_logtail now accepts an optional if=$variable parameter
  that suppresses log lines when the variable is empty or "0",
  following the same semantics as nginx's access_log if=. The
  condition is checked before format rendering for zero overhead on
  filtered requests. Filtered requests are still counted by stats.
- Log format examples updated to include $scheme for http/https
  visibility, and renamed to ipng_stats_logtail to match production.
- Robot test added for the if= filter (19 tests, 19 pass).
- FR-8.5 added to design doc for the if= semantics.
This commit is contained in:
2026-04-16 18:49:13 +02:00
parent 5a7e2f77f1
commit 87050bcf13
6 changed files with 124 additions and 30 deletions

View File

@@ -122,20 +122,21 @@ endpoint does not inflate its own counters.
See FR-5.5.
### `ipng_stats_logtail <format_name> udp://<host>:<port> [buffer=<size>] [flush=<duration>]`
### `ipng_stats_logtail <format_name> udp://<host>:<port> [buffer=<size>] [flush=<duration>] [if=<$variable>]`
**Context:** `http`.
**Value:** `<format_name>` is the name of an existing `log_format` defined earlier in the same `http` block. The destination MUST be a
`udp://host:port` URI. `buffer=<size>` is an optional nginx size spec (default `64k`, minimum `1k`). `flush=<duration>` is an optional
nginx duration string (default `1s`, minimum `100ms`).
nginx duration string (default `1s`, minimum `100ms`). `if=<$variable>` is an optional condition variable — when set, the log line is
only emitted if the variable evaluates to a non-empty value other than `"0"`.
**Default:** not set — the directive is optional. When absent, no global logtail output is written.
**Effect:** registers a global log-phase writer that fires unconditionally for every request, regardless of `server` or `location`
context. The named `log_format` is looked up from nginx's log module at configuration time; nginx's standard variable-expansion
machinery renders each line, so any variable usable in a regular `log_format` — including `$ipng_source_tag` and `$server_addr` — is
available here.
**Effect:** registers a global log-phase writer that fires unconditionally for every request (unless suppressed by `if=`), regardless
of `server` or `location` context. The named `log_format` is looked up from nginx's log module at configuration time; nginx's standard
variable-expansion machinery renders each line, so any variable usable in a regular `log_format` — including `$ipng_source_tag` and
`$server_addr` — is available here.
Each worker maintains a private in-memory write buffer of `buffer=<size>` bytes. Each buffer flush is transmitted as a single
`sendto()` call on a per-worker `SOCK_DGRAM` socket that is opened at worker init and closed at worker exit. The address is resolved
@@ -152,12 +153,31 @@ in every log line at no extra configuration cost.
File-based access logging is intentionally not supported by this directive — use nginx's built-in `access_log` directive for that.
```nginx
log_format logtail '$host\t$remote_addr\t$ipng_source_tag\t$server_addr\t'
'$request_method\t$request_uri\t$status\t$body_bytes_sent\t'
'$request_time';
ipng_stats_logtail logtail udp://127.0.0.1:9514 buffer=16k flush=1s;
log_format ipng_stats_logtail '$host\t$remote_addr\t$request_method\t$request_uri\t'
'$status\t$body_bytes_sent\t'
'$ipng_source_tag\t$server_addr\t$scheme';
ipng_stats_logtail ipng_stats_logtail udp://127.0.0.1:9514 buffer=16k flush=1s;
```
#### Conditional logging with `if=`
The `if=$variable` parameter suppresses log lines for requests where the variable is empty, not found, or `"0"`. This uses the same
semantics as nginx's built-in `access_log ... if=` and works well with `map` blocks:
```nginx
# Suppress health checks from the logtail stream:
map $request_uri $logtail_enabled {
~^/\.well-known/ipng/healthz 0;
default 1;
}
ipng_stats_logtail ipng_stats_logtail udp://127.0.0.1:9514 if=$logtail_enabled;
```
The `map` compiles to a hash table at configuration time; at request time it costs a single hash probe, evaluated lazily only when
the variable is read. The condition is checked before the log format is rendered, so filtered requests skip the format rendering
entirely.
**Constraints and behavior:**
- `host` MUST be a literal IPv4 address. Hostnames and IPv6 addresses are not supported in v0.1.