Add ASN to logtail, collector, aggregator, frontend and CLI
This commit is contained in:
@@ -27,7 +27,7 @@ Add the `logtail` log format to your `nginx.conf` and apply it to each `server`
|
||||
|
||||
```nginx
|
||||
http {
|
||||
log_format logtail '$host\t$remote_addr\t$msec\t$request_method\t$request_uri\t$status\t$body_bytes_sent\t$request_time\t$is_tor';
|
||||
log_format logtail '$host\t$remote_addr\t$msec\t$request_method\t$request_uri\t$status\t$body_bytes_sent\t$request_time\t$is_tor\t$asn';
|
||||
|
||||
server {
|
||||
access_log /var/log/nginx/access.log logtail;
|
||||
@@ -38,10 +38,16 @@ http {
|
||||
```
|
||||
|
||||
The format is tab-separated with fixed field positions. Query strings are stripped from the URI
|
||||
by the collector at ingest time — only the path is tracked. `$is_tor` must be set to `1` when
|
||||
the client IP is a TOR exit node and `0` otherwise (this is typically populated by a custom nginx
|
||||
variable or a Lua script that checks the IP against a TOR exit list). The field is optional for
|
||||
backward compatibility — log lines without it are accepted and treated as `is_tor=0`.
|
||||
by the collector at ingest time — only the path is tracked.
|
||||
|
||||
`$is_tor` must be set to `1` when the client IP is a TOR exit node and `0` otherwise (typically
|
||||
populated by a custom nginx variable or a Lua script that checks the IP against a TOR exit list).
|
||||
The field is optional for backward compatibility — log lines without it are accepted and treated
|
||||
as `is_tor=0`.
|
||||
|
||||
`$asn` must be set to the client's AS number as a decimal integer (e.g. from MaxMind GeoIP2's
|
||||
`$geoip2_data_autonomous_system_number`). The field is optional — log lines without it default
|
||||
to `asn=0`.
|
||||
|
||||
---
|
||||
|
||||
@@ -128,7 +134,7 @@ The collector is designed to stay well under 1 GB:
|
||||
| Coarse ring (288 × 5-min) | 288 × 5 000 | ~268 MB |
|
||||
| **Total** | | **~845 MB** |
|
||||
|
||||
When the live map reaches 100 000 distinct 5-tuples, new keys are dropped for the rest of that
|
||||
When the live map reaches 100 000 distinct 6-tuples, new keys are dropped for the rest of that
|
||||
minute. Existing keys continue to accumulate counts. The cap resets at each minute rotation.
|
||||
|
||||
### Time windows
|
||||
@@ -252,13 +258,13 @@ the selected dimension and time window.
|
||||
**Window tabs** — switch between `1m / 5m / 15m / 60m / 6h / 24h`. Only the window changes;
|
||||
all active filters are preserved.
|
||||
|
||||
**Dimension tabs** — switch between grouping by `website / prefix / uri / status`.
|
||||
**Dimension tabs** — switch between grouping by `website / asn / prefix / status / uri`.
|
||||
|
||||
**Drilldown** — click any table row to add that value as a filter and advance to the next
|
||||
dimension in the hierarchy:
|
||||
|
||||
```
|
||||
website → client prefix → request URI → HTTP status → website (cycles)
|
||||
website → client prefix → request URI → HTTP status → ASN → website (cycles)
|
||||
```
|
||||
|
||||
Example: click `example.com` in the website view to see which client prefixes are hitting it;
|
||||
@@ -282,17 +288,21 @@ website=example.com AND prefix=1.2.3.0/24
|
||||
|
||||
Supported fields and operators:
|
||||
|
||||
| Field | Operators | Example |
|
||||
|-----------|---------------------|----------------------------|
|
||||
| `status` | `=` `!=` `>` `>=` `<` `<=` | `status>=400` |
|
||||
| `website` | `=` `~=` | `website~=gouda.*` |
|
||||
| `uri` | `=` `~=` | `uri~=^/api/` |
|
||||
| `prefix` | `=` | `prefix=1.2.3.0/24` |
|
||||
| `is_tor` | `=` `!=` | `is_tor=1`, `is_tor!=0` |
|
||||
| Field | Operators | Example |
|
||||
|-----------|---------------------|-----------------------------------|
|
||||
| `status` | `=` `!=` `>` `>=` `<` `<=` | `status>=400` |
|
||||
| `website` | `=` `~=` | `website~=gouda.*` |
|
||||
| `uri` | `=` `~=` | `uri~=^/api/` |
|
||||
| `prefix` | `=` | `prefix=1.2.3.0/24` |
|
||||
| `is_tor` | `=` `!=` | `is_tor=1`, `is_tor!=0` |
|
||||
| `asn` | `=` `!=` `>` `>=` `<` `<=` | `asn=8298`, `asn>=1000` |
|
||||
|
||||
`is_tor=1` and `is_tor!=0` are equivalent (TOR traffic only). `is_tor=0` and `is_tor!=1` are
|
||||
equivalent (non-TOR traffic only).
|
||||
|
||||
`asn` accepts the same comparison expressions as `status`. Use `asn=8298` to match a single AS,
|
||||
`asn>=64512` to match the private-use ASN range, or `asn!=0` to exclude unresolved entries.
|
||||
|
||||
`~=` means RE2 regex match. Values with spaces or quotes may be wrapped in double or single
|
||||
quotes: `uri~="^/search\?q="`.
|
||||
|
||||
@@ -311,8 +321,8 @@ accept RE2 regular expressions. The breadcrumb strip shows them as `website~=gou
|
||||
`uri~=^/api/` with the usual `×` remove link.
|
||||
|
||||
**URL sharing** — all filter state is in the URL query string (`w`, `by`, `f_website`,
|
||||
`f_prefix`, `f_uri`, `f_status`, `f_website_re`, `f_uri_re`, `f_is_tor`, `n`). Copy the URL to
|
||||
share an exact view with another operator, or bookmark a recurring query.
|
||||
`f_prefix`, `f_uri`, `f_status`, `f_website_re`, `f_uri_re`, `f_is_tor`, `f_asn`, `n`). Copy
|
||||
the URL to share an exact view with another operator, or bookmark a recurring query.
|
||||
|
||||
**JSON output** — append `&raw=1` to any URL to receive the TopN result as JSON instead of
|
||||
HTML. Useful for scripting without the CLI binary:
|
||||
@@ -368,6 +378,7 @@ logtail-cli targets [flags] list targets known to the queried endpoint
|
||||
| `--website-re`| — | Filter: RE2 regex against website |
|
||||
| `--uri-re` | — | Filter: RE2 regex against request URI |
|
||||
| `--is-tor` | — | Filter: `1` or `!=0` = TOR only; `0` or `!=1` = non-TOR only |
|
||||
| `--asn` | — | Filter: ASN expression (`12345`, `!=65000`, `>=1000`, `<64512`, …) |
|
||||
|
||||
### `topn` flags
|
||||
|
||||
@@ -375,7 +386,7 @@ logtail-cli targets [flags] list targets known to the queried endpoint
|
||||
|---------------|------------|----------------------------------------------------------|
|
||||
| `--n` | `10` | Number of entries |
|
||||
| `--window` | `5m` | `1m` `5m` `15m` `60m` `6h` `24h` |
|
||||
| `--group-by` | `website` | `website` `prefix` `uri` `status` |
|
||||
| `--group-by` | `website` | `website` `prefix` `uri` `status` `asn` |
|
||||
|
||||
### `trend` flags
|
||||
|
||||
@@ -470,6 +481,21 @@ logtail-cli topn --target agg:9091 --window 5m --is-tor 1
|
||||
# Show non-TOR traffic only — exclude exit nodes from the view
|
||||
logtail-cli topn --target agg:9091 --window 5m --is-tor 0
|
||||
|
||||
# Top ASNs by request count over the last 5 minutes
|
||||
logtail-cli topn --target agg:9091 --window 5m --group-by asn
|
||||
|
||||
# Which ASNs are generating the most 429s?
|
||||
logtail-cli topn --target agg:9091 --window 5m --group-by asn --status 429
|
||||
|
||||
# Filter to traffic from a specific ASN
|
||||
logtail-cli topn --target agg:9091 --window 5m --asn 8298
|
||||
|
||||
# Filter to traffic from private-use / unallocated ASNs
|
||||
logtail-cli topn --target agg:9091 --window 5m --group-by prefix --asn '>=64512'
|
||||
|
||||
# Exclude unresolved entries (ASN 0) and show top source ASNs
|
||||
logtail-cli topn --target agg:9091 --window 5m --group-by asn --asn '!=0'
|
||||
|
||||
# Compare two collectors side by side in one command
|
||||
logtail-cli topn --target nginx1:9090,nginx2:9090 --window 5m
|
||||
|
||||
|
||||
Reference in New Issue
Block a user