Statistics and metrics collection configuration for monitoring and performance analysis
statistics
The statistics clause configures counter and histogram retention and history settings for
dynamic metric creation. Counters are dynamically created when first incremented via
the count action or context.count() in scripts—no pre-declaration required.
Histograms are dynamically created internally for latency tracking in backends, handlers, and policies.
This configuration controls:
- History retention (
samples) for counter and histogram time series - Update interval (
interval) for history snapshots - Namespace-based pattern matching for applying settings to groups of counters and histograms
Basic Example
statistics {
defaults {
samples 288; # keep last 288 history snapshots (24h at 5m)
interval 5m; # 5 minutes between snapshots
}
# Configure all counters ending with "::requests"
counter /.*::requests/ {
samples 2880; # 24 hours at 30s intervals
interval 30s; # higher granularity
}
# Configure all backend latency histograms
histogram /backend::.*::latency/ {
samples 720; # 6 hours at 30s intervals
interval 30s;
}
# Configure specific counter with exact namespace match
# Note: Exact matches have highest priority
counter "handler::AUTH_SERVER::DEFAULT::PAP_HANDLER::auth_attempts" {
samples 1440; # 24 hours at 1m intervals
}
}
Elements
| Block / Statement | Context | Required | Description |
|---|---|---|---|
statistics { ... } | top level | Yes | Container for counter and histogram history configuration |
defaults { ... } | statistics | No | Sets fallback samples / interval for all counters & histograms |
counter /pattern/ { ... } | statistics | No | Configures counters matching regex pattern |
histogram /pattern/ { ...} | statistics | No | Configures histograms matching regex pattern |
samples N; | defaults / counter / histogram | No | History buffer length (number of snapshots retained) |
interval DURATION; | defaults / counter / histogram | No | Snapshot interval (supports: ms, s, m, h, d, w, M, y) |
Pattern Matching
Counter and histogram patterns use namespace paths separated by :: and must be written as regex patterns using forward slash syntax: /pattern/ or /pattern/flags.
Regex Pattern Syntax
All patterns use Rust regex syntax:
- Written with forward slashes:
/pattern/or/pattern/flags - Supports regex flags:
i(case-insensitive),m(multiline),s(dot matches newline) - Performs partial matching by default (matches anywhere in the namespace path)
- Use anchors
^and$for exact full-string matches
Pattern Examples
Partial matching (default):
/handler::/– matches any namespace path containing "handler::"/::errors/– matches any path with "::errors" anywhere/latency/– matches any path containing "latency"/(success|failure)_count/– matches paths with either "success_count" or "failure_count"
Exact matching with anchors:
/^handler::.*::accept$/– full path must start with "handler::" and end with "accept"/^.*::errors$/– matches paths ending with "::errors" (counter named "errors")/^backend::SQL::.*::latency$/– SQL backend latency histograms only/^custom::metrics::login_count$/– exact full namespace match
With regex flags:
counter /handler::.*/i {
# Case-insensitive: matches "HANDLER::", "Handler::", etc.
samples 600;
}
Supported flags: i (case-insensitive), m (multiline), s (dot matches newline)
Evaluation Order
Patterns are evaluated in the order they appear in the configuration file:
- Patterns are checked sequentially from top to bottom
- First matching pattern wins for each counter/histogram
- Counters that don't match any pattern use
defaults - Order matters! Place more specific patterns before general ones
Example:
statistics {
# More specific pattern first
counter /^handler::.*::errors$/ {
samples 2880; # 24h retention for error counters
}
# General handler pattern second
counter /^handler::/ {
samples 600; # 10h retention for other handler counters
}
}
In this example, handler::DEFAULT::errors matches the first pattern (2880 samples), while handler::DEFAULT::requests matches the second (600 samples).
Ordering & Inheritance
defaultsaffects all counters/histograms unless overridden by specific patterns- Patterns are evaluated sequentially in the order they appear in the config file
- First matching pattern wins for each counter/histogram
- Place more specific patterns before general ones to avoid unexpected matches
- Multiple
defaultsblocks: first one is used, subsequent generate warnings
Dynamic Counter Creation
Counters are created automatically when incremented via the count action.
See the count action documentation for usage examples and namespaces for hierarchy details.
Quick summary:
- Counters without
::inherit the current context namespace - Counters with
::create custom namespace hierarchies - Available in both radconf (
count "name") and Lua scripts (context.count("name"))
Counter Example
statistics {
defaults {
samples 288; # 24 hours at 5m intervals
interval 5m;
}
# Exact match takes priority (checked first)
counter "critical_auth" {
samples 8640; # 24 hours at 10s intervals
interval 10s; # high resolution
}
# Regex pattern for all authentication counters
# Pattern matches anywhere in the full namespace path
counter /.*::auth.*/ {
samples 2880; # 24 hours at 30s intervals
interval 30s; # moderate resolution
}
# Regex pattern evaluated second
counter /.*::error/ {
samples 1440; # 24 hours at 1m intervals
}
}
Pattern Matching Examples
With the configuration above, counters are matched as follows:
| Counter Path | Matched By | Match Type | Samples | Interval |
|---|---|---|---|---|
server::radius::critical_auth | "critical_auth" | Exact (last component name) | 8640 | 10s |
handler::DEFAULT::auth_success | /.*::auth.*/ | Regex (contains "auth") | 2880 | 30s |
backend::SQL::error | /.*::error/ | Regex (ends with "error") | 1440 | 1m |
custom::critical_auth::attempts | /.*::auth.*/ | Regex (not exact, "critical_auth" in path) | 2880 | 30s |
Note: The exact match "critical_auth" only matches when it appears as the last component of the namespace path.
Histograms
Histograms track latency distributions for backends, handlers, and policies. They are automatically created internally when components are initialized (no user declaration required).
Histograms use HDRHistogram for high-dynamic-range latency recording. Buckets are not configurable - HDRHistogram automatically manages bucket boundaries to provide accurate percentile calculations across a wide range of latencies (microseconds to hours) while maintaining a fixed memory footprint (~176KB per histogram).
Histogram Data
Each histogram provides quantile values (p25, p50, p75, p80, p90, p95, p99, p100/max) that represent latency percentiles in microseconds. For example:
- p50 (median): 50% of requests completed faster than this value
- p95: 95% of requests completed faster than this value
- p99: 99% of requests completed faster than this value
- p100 (max): Maximum observed latency in the current recording window
These quantiles are exposed via the Management API:
GET /api/v1/statistics/histogram/{namespace}
# Returns: [p25, p50, p75, p80, p90, p95, p99, p100]
Histogram Configuration
Histogram configuration uses the same pattern matching system as counters to configure time series history:
statistics {
defaults {
samples 288; # 24 hours at 5m intervals (for histograms too)
interval 5m;
}
# Configure all SQL backend latency histograms
histogram /backend::SQL::.*::latency/ {
samples 720; # 6 hours at 30s intervals
interval 30s;
}
# Configure specific handler latency with exact match
histogram /^handler::DEFAULT::RADIUS_AUTH::latency$/ {
samples 2880; # 24 hours at 30s intervals
interval 30s;
}
}
Note: Only samples and interval parameters are valid for histograms. Bucket boundaries are managed automatically by HDRHistogram and cannot be configured.
Histogram Namespace Examples:
backend::SQL::DB_01::latency– SQL backend latencybackend::RADIUS::UPSTREAM::latency– RADIUS backend latencyhandler::DEFAULT::RADIUS_AUTH::latency– Handler execution timepolicy::POLICY_01::latency– Policy execution time
Legacy Syntax:
The legacy histogram "name" { } declaration syntax (without pattern matching or :: in the name) is not supported and will generate a warning. Use pattern-based configuration as shown above instead.
Retention (samples)
samples defines how many history snapshots to retain per counter. Each snapshot
captures the counter value at one interval boundary.
Memory usage: samples × active_counter_count × ~32 bytes per entry
Choose values based on:
- Monitoring window: 300 samples at 60s = 5 hours of history
- Resolution needs: More samples = finer trend analysis
- Memory constraints: More counters = reduce samples or increase interval
Typical configurations:
- Short-term diagnostics: 300 samples (5 min at 1s, or 5 hours at 60s)
- Production monitoring: 600-1440 samples (10-24 hours at 60s)
- Long-term trending: 2880+ samples (48+ hours at 60s)
Interval (interval)
interval controls how often counter values are captured into history snapshots.
Supported formats:
- Time units:
10s,1m,5m,1h,30s(recommended) - Milliseconds:
60000(raw number defaults to milliseconds) - Combinations:
1h30m,10m20s(multiple units can be combined)
Supported units: ms (milliseconds), s (seconds), m (minutes), h (hours),
d (days), w (weeks), M (months/30 days), y (years/365 days)
Trade-offs:
| Interval | Pro | Con |
|---|---|---|
| 1-10s | High resolution, spot spikes | More CPU overhead, noisy data |
| 30-60s | Balanced resolution/overhead | Good for general monitoring |
| 300s+ | Low overhead, smooth trends | May miss short-duration spikes |
Recommendations:
- Critical paths:
10sto30sfor authentication/authorization handlers - Background metrics:
1mto5mfor less critical counters - Long-term trends:
5mor longer for daily/weekly aggregation
See namespaces documentation for complete details on namespace structure and hierarchy.
Example paths:
- Handler counter:
handler::AUTH_SERVER::DEFAULT::PAP_HANDLER::accept - Custom counter:
custom::app::requests
Additionally, counters are exposed in hierarchical format via:
# Get counter tree with namespace hierarchy
GET /api/v1/clog/summary?ns=handler::AUTH_SERVER::DEFAULT