Metric#
The Counting API requests: If a request is made to The Default — http Creates a shared memory zone of the specified size with the given name
to store metrics. The zone name serves as a node in the
Parameters: free memory for new ones; preserving existing entries. where values of discarded metrics are accumulated. By default, no such
metric is created. Reserved key cannot be updated manually. mode — data processing algorithm (see the Operation Modes section); (e.g., Example usage: In the API tree, the shared memory zone template looks as follows: Number; the count of discarded metrics in the shared memory zone Object; its members are metrics with defined keys and calculated values Note In a 1 MB zone, with a key size of 39 bytes and a single metric mode,
approximately 8,000 unique key entries can be stored. Default — http Defines a complex metric — a set of metrics with independent modes.
Each line in the block body defines a submetric name, a mode,
and optional mode parameters. Example usage: In the API tree, such a complex metric template looks as follows: Number; the count of discarded metrics in the shared memory zone Object; its members are complex metrics with set keys. They are objects containing a set of submetrics with calculated values Calculates the value of the metric for the specified shared memory zone name. Parameters: Maximum length is 255 bytes. If the key is longer, it will be truncated
to 255 bytes and appended with an ellipsis If omitted, it defaults to If If If Note In the case of internal redirection, metrics at the Example usage: Note Metrics with an empty key or an invalid This is useful, for example, for the Note Remember that variables are evaluated in different phases. For example,
it is impossible to use List of available metric operation modes: The counter increases its value by Default value — Note Any metric update (with any value) monotonically increases the counter by Examples: Updating the metric: Expected metric value in the API: The gauge increases or decreases its value depending on the sign of the
passed number. A positive value increases the counter, while a negative
value decreases it. A value of Default value — Examples: Updating the metric: Expected metric value in the API: Further updates: Expected metric value in the API: Stores the last received value without any aggregation. If value is
omitted, Examples: Updating the metric: Expected metric value in the API: Further updates: Expected metric value in the API: Saves the minimum of two values — the currently stored value and the new one. Examples: Updating the metric: Expected metric value in the API: Saves the maximum of two values — the currently stored value and the new one. Examples: Updating the metric: Expected metric value in the API: Calculates the average value using the
exponential smoothing algorithm. Accepts an optional parameter The higher the coefficient, the more weight new values have. If you specify
Examples: Updating the metric: Expected metric value in the API: Calculates the arithmetic mean. Accepts optional parameters
Note For example, Examples: Updating the metric: Expected metric value in the API: If you wait 5 seconds from the last update, the expected value will be: Creates a set of "buckets," incrementing the relevant counter if the new
value does not exceed the bucket threshold. Parameters are provided as
a list of numerical thresholds. Useful for analyzing distributions,
such as response times. Mandatory parameters are numbers — the threshold values of the buckets,
listed in ascending order. Note The bucket value Examples: Updating the metric: Expected metric value in the API: Further updates: Expected metric value in the API: Further update: Expected metric value in the API: Variables are created for each metric: For complex metrics, an additional variable is added: Similar to the metric directive, the The value used for setting the variable must follow the Example usage: Calculating metrics using the
njs module: File After several requests to Note After setting the variable, you can retrieve its value; it will equal
the specified Additionally, the value stored in the The Note For complex metrics, the submetric values in the Example usage: With this configuration, a request to For Note If an empty string is assigned to Calculation occurs only after both In this case, the value stored in The value in The value in For complex metrics, the value of a specific submetric can be retrieved
using the Example usage: With this configuration, a request to Response: Response: Response: Angie includes a built-in module for displaying
metrics in
Prometheus format,
which supports custom metrics. As an integration example, consider the following configuration: After several requests to The metric values will be: In Prometheus format,
the metric is available at ngx_http_metric_module module allows creating arbitrary real-time
calculated metrics. These metric values are stored in shared memory and displayed
in real-time within the /status/http/metric_zones/ API branch.
Various data aggregation types are supported (counters, histograms, moving averages, etc.)
with grouping by arbitrary keys.Configuration Example#
http {
metric_zone api_requests:1m count;
server {
listen 80;
location /api/ {
allow 127.0.0.1;
deny all;
api /;
metric api_requests $http_user_agent on=request;
}
}
}
/api/ with this configuration:$ curl 127.0.0.1/api/ --user-agent "Firefox"
api_requests metric is updated in real-time:{
"status": {
"http": {
"metric_zones": {
"api_requests": {
"discarded": 0,
"metrics": {
"Firefox": 1
}
}
}
}
}
}
Directives#
metric_zone#
metric_zone name:size [expire=on|:samp:off] [discard_key=name] mode [parameters];/status/http/metric_zones/ branch.expire=<on|off> — behavior when the zone is full:on, the oldest metrics (by update time) are discarded tooff (default) — new incoming metrics are discarded,discard_key=<name> — defines a metric with the key namefactor for average exp).metric_zone request_time:1m max;
{
"discarded": 0,
"metrics": {
"key1": 123,
"key2": 10.5,
}
}
discardedmetricsmetric_complex_zone#
metric_complex_zone name:size [expire=on|:samp:off] [discard_key=name] { ... }metric_complex_zone requests:1m expire=on discard_key="old" {
# submetric name mode parameters
min_time min;
avg_time average exp factor=60;
max_time max;
total count;
}
{
"discarded": 3,
"metrics": {
"key1": {
"min_time": 20,
"avg_time": 50,
"max_time": 80,
"total" 2
},
"old": {
"min_time": 3,
"avg_time": 40,
"max_time": 152,
"total": 80
}
}
}
discardedmetricsmetric#
...;0. If the parameter cannot be
converted to a number, it defaults to 1;on — an optional parameter specifying when the metric is calculated:on=request, calculation occurs when the request is received;on=response, calculation occurs during response preparation;on=end (default), calculation occurs after the response is sent.on=request
stage are calculated in the original location. However,
on=response and on=end metrics will be calculated
in the new location.metric requests $http_user_agent=$request_time;
key=value pair are ignored.
An omitted value is treated as 0:metric foo $bar; # Equivalent to $bar=0
count mode, which ignores
numerical values and simply reacts to the fact that a metric was updated.$bytes_sent (bytes sent to the client)
with on=request (when the request is received).Operation Modes#
count — counter;gauge — gauge (increment/decrement);last — the last received value;min — minimum value;max — maximum value;average exp — exponential moving average (EMA) (parameter factor);average mean — mean over a window (parameters window and count);histogram — distribution across "buckets" (a list of threshold values).count#
1 with every metric update.0.1.metric_zone count:1m count;
# As part of a complex metric:
#
# metric_complex_zone count:1m {
# some_metric_name count;
# }
server {
listen 80;
location /metric/ {
metric count KEY;
}
location ~ ^/metric/set/(.+)$ {
metric count KEY=1;
}
location /api/ {
api /status/http/metric_zones/count/metrics/;
}
}
$ curl 127.0.0.1/metric/
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/set/23
$ curl 127.0.0.1/metric/set/-32
{
"KEY": 4
}
gauge#
0 does not change the counter.0.metric_zone gauge:1m gauge;
# As part of a complex metric:
#
# metric_complex_zone gauge:1m {
# some_metric_name gauge;
# }
server {
listen 80;
location /metric/ {
metric gauge KEY;
}
location ~ ^/metric/set/(.+)$ {
metric gauge KEY=$1;
}
location /api/ {
api /status/http/metric_zones/gauge/metrics/;
}
}
$ curl 127.0.0.1/metric/
{
"KEY": 0
}
$ curl 127.0.0.1/metric/set/5
$ curl 127.0.0.1/metric/set/-5
$ curl 127.0.0.1/metric/set/8
{
"KEY": 8
}
last#
0 is used.metric_zone last:1m last;
# As part of a complex metric:
#
# metric_complex_zone last:1m {
# some_metric_name last;
# }
server {
listen 80;
location /metric/ {
metric last KEY;
}
location ~ ^/metric/set/(.+)$ {
metric last KEY=$1;
}
location /api/ {
api /status/http/metric_zones/last/metrics/;
}
}
$ curl 127.0.0.1/metric/
{
"KEY": 0
}
$ curl 127.0.0.1/metric/set/8000
$ curl 127.0.0.1/metric/set/37
$ curl 127.0.0.1/metric/set/-3.5
{
"KEY": -3.5
}
min#
metric_zone min:1m min;
# As part of a complex metric:
#
# metric_complex_zone min:1m {
# some_metric_name min;
# }
server {
listen 80;
location /metric/ {
metric min KEY;
}
location ~ ^/metric/set/(.+)$ {
metric min KEY=$1;
}
location /api/ {
api /status/http/metric_zones/min/metrics/;
}
}
$ curl 127.0.0.1/metric/set/42.999
$ curl 127.0.0.1/metric/set/-512
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/
{
"KEY": -512
}
max#
metric_zone max:1m max;
# As part of a complex metric:
#
# metric_complex_zone max:1m {
# some_metric_name max;
# }
server {
listen 80;
location /metric/ {
metric max KEY;
}
location ~ ^/metric/set/(.+)$ {
metric max KEY=$1;
}
location /api/ {
api /status/http/metric_zones/max/metrics/;
}
}
$ curl 127.0.0.1/metric/set/42.999
$ curl 127.0.0.1/metric/set/-512
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/
{
"KEY": 42.999
}
average exp#
factor=<number> — a coefficient determining
how much the new value influences the average. Integer values from 0 to
99 are allowed. Default is 90.90, the result will be 90% of the new value and 10%
of the previous average.metric_zone avg_exp:1m average exp factor=60;
# As part of a complex metric:
#
# metric_complex_zone avg_exp:1m {
# some_metric_name average exp factor=60;
# }
server {
listen 80;
location ~ ^/metric/set/(.+)$ {
metric avg_exp KEY=$1;
}
location /api/ {
api /status/http/metric_zones/avg_exp/metrics/;
}
}
$ curl 127.0.0.1/metric/set/100
$ curl 127.0.0.1/metric/set/200
$ curl 127.0.0.1/metric/set/0
$ curl 127.0.0.1/metric/set/8
$ curl 127.0.0.1/metric/set/30
{
"KEY": 30.16
}
average mean#
window=<off|time> and count=<number>, defining the
time interval and sample size for averaging, respectively.
Defaults: window=off (entire sample used) and count=10.window=5s will only consider events from the last 5 seconds.
The window parameter cannot be 0. The count=number
parameter controls the sample size (cached values) for a smoother mean calculation.metric_zone avg_mean:1m average mean window=5s count=8;
# As part of a complex metric:
#
# metric_complex_zone avg_mean:1m {
# some_metric_name average mean window=5s count=8;
# }
server {
listen 80;
location ~ ^/metric/set/(.+)$ {
metric avg_mean KEY=$1;
}
location /api/ {
api /status/http/metric_zones/avg_mean/metrics/;
}
}
$ curl 127.0.0.1/metric/set/0.1
$ curl 127.0.0.1/metric/set/0.1
$ curl 127.0.0.1/metric/set/0.4
$ curl 127.0.0.1/metric/set/10
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/set/1
{
"KEY": 2.1
}
{
"KEY": 0
}
histogram#
inf or +Inf can be used to capture all
values exceeding the highest specified bucket.metric_zone hist:1m histogram 0.1 0.2 0.5 1 2 inf;
# As part of a complex metric:
#
# metric_complex_zone hist:1m {
# some_metric_name histogram 0.1 0.2 0.5 1 2 inf;
# }
server {
listen 80;
location ~ ^/metric/set/(.+)$ {
metric histogram KEY=$1;
}
location /api/ {
api /status/http/metric_zones/hist/metrics/;
}
}
$ curl 127.0.0.1/metric/set/0.25
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 1,
"inf": 1
}
}
$ curl 127.0.0.1/metric/set/2
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 2
}
}
$ curl 127.0.0.1/metric/set/1000
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 3
}
}
Built-in Variables#
$metric_<name>$metric_<name>_key$metric_<name>_value$metric_<name>_value_<metric>$metric_<name>#$metric_<name>
variable setter can be used to update a metric. Calculation occurs during the
Rewrite phase,
allowing metric processing from the njs module, for example.key=value structure.
Both key and value can consist of text, variables, and combinations thereof.
The key is an arbitrary string for grouping values. The value is a number
processed by the selected mode. If omitted, it defaults to 0.
If the parameter cannot be converted to a number, it defaults to 1.http {
metric_zone counter:1m count;
# At this point, the $metric_counter variable is added
server {
listen 80;
location /metric/ {
set $metric_counter $http_user_agent; # Equivalent to $http_user_agent=0
}
location /api/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/counter/;
}
}
}
http {
js_import metrics.js;
resolver 127.0.0.53;
metric_complex_zone requests:1m {
min_time min;
max_time max;
total count;
}
location /metric/ {
js_content metrics.js_request;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}
location /api/ {
allow 127.0.0.1;
deny all;
api /static/http/metric_zones/requests/;
}
}
metrics.js:async function js_request(r) {
let start_time = Date.now();
let results = await Promise.all([ngx.fetch('https://google.com/'),
ngx.fetch('https://google.ru/')]);
// Using the $metric_requests variable setter
r.variables.metric_requests = `google={Date.now() - start_time}`;
}
export default {js_request};
location /metric/, the values might look like this:{
"discarded": 0,
"metrics": {
"google": {
"min_time": 70,
"max_time": 432,
"total": 6
}
}
}
key=value pair.$metric_<name>_key variable
will change to the specified key.$metric_<name>_key and $metric_<name>_value#$metric_<name>_key and $metric_<name>_value variables
define the key and value respectively. The metric update occurs when the
$metric_<name>_value is set, provided that the key in
$metric_<name>_key has already been defined.$metric_<name>_value
variable are joined using a ", " separator.http {
metric_zone gauge:1m gauge;
# The variables $metric_gauge, $metric_gauge_key, and $metric_gauge_value are added here.
metric_complex_zone complex:1m {
hist histogram 1 2 3;
avg average exp;
}
# $metric_complex, $metric_complex_key, and $metric_complex_value are added here.
server {
listen 80;
location /gauge/ {
set $metric_gauge_key "foo";
set $metric_gauge_value 1;
# Or: set $metric_gauge foo=1;
return 200 "Updated with '$metric_gauge'\nValue='$metric_gauge_value'\n";
}
location /complex/ {
set $metric_complex_key "foo";
set $metric_complex_value 3;
# Or: set $metric_complex foo=3;
return 200 "Updated with '$metric_complex'\nValue='$metric_complex_value'\n";
}
}
}
/gauge/ yields:$ curl 127.0.0.1/gauge/
Updated with 'foo=1'
Value='1'
/complex/:$ curl 127.0.0.1/complex/
Updated with 'foo=3'
Value='0 0 1, 3'
$metric_<name>_value, the value is
recognized as 0. If the string consists of characters that cannot be
converted to a number, it is recognized as 1.$metric_<name>_key and
$metric_<name>_value have been set.$metric_<name> becomes equal
to the new key=value pair.$metric_<name>_key represents the last key specified
via variables.$metric_<name>_value represents the last calculated
value for the key set in $metric_<name>_key.$metric_<name>_value_<metric>#$metric_<name>_value_<metric> variable, where
<metric> is the name of the submetric.http {
metric_complex_zone foo:1m {
count count;
min min;
avg average exp;
}
# Adds $metric_foo, $metric_foo_key, $metric_foo_value,
# and $metric_foo_value_count, $metric_foo_value_min, $metric_foo_value_avg.
server {
listen 80;
location /foo/ {
set $metric_foo_key bar;
set $metric_foo_value 9;
# Or: set $metric_foo bar=9;
return 200 "Updated with '$metric_foo'\nValues='$metric_foo_value'\nCount='$metric_foo_value_count'\n";
}
}
}
/foo/ yields:$ curl 127.0.0.1/foo/
Updated with 'bar=9'
Values='1, 9, 9'
Count='1'
Additional Examples#
Monitoring HTTP Methods#
metric_zone http_methods:1m count;
server {
listen 80;
location / {
metric http_methods $request_method;
}
location /metrics/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/http_methods/metrics/;
}
}
{
"GET": 65,
"POST": 20,
"PUT": 10,
"DELETE": 5
}
Upstream Response Time Distribution#
metric_zone upstream_time:10m expire=on histogram
0.05 0.1 0.3 0.5 1 2 5 10 inf;
server {
listen 80;
location /backend/ {
proxy_pass http://backend;
metric upstream_time $upstream_addr=$upstream_response_time on=end;
}
location /metrics/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/upstream_time/;
}
}
{
"discarded": 0,
"metrics": {
"backend1:8080": {
"0.05": 12,
"0.1": 28,
"0.3": 56,
"0.5": 78,
"1": 92,
"2": 97,
"5": 99,
"10": 100,
"inf": 100
}
}
}
Active Connections#
metric_zone active_connections:2m gauge;
server {
listen 80;
server_name site1.com;
location / {
# Увеличиваем при подключении
metric active_connections site1=1 on=request;
# Уменьшаем при завершении
metric active_connections site1=-1 on=end;
}
}
server {
listen 80;
server_name site2.com;
location / {
metric active_connections site2=1 on=request;
metric active_connections site2=-1 on=end;
}
}
server {
listen 8080;
location /connections/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/active_connections/metrics;
}
}
{
"site1": 42,
"site2": 17
}
Prometheus Support#
http {
# Creating the "upload" metric
metric_complex_zone upload:1m discard_key="other" {
stats histogram 64 256 1024 4096 16384 +Inf;
sum gauge;
count count;
avg_size average exp;
}
# Describing the Prometheus template for the "upload" metric
prometheus_template upload_metric {
'stats{le="$1"}' $p8s_value
path=~^/http/metric_zones/upload/metrics/angie/stats/(.+)$
type=histogram;
'stats_sum' $p8s_value
path=/http/metric_zones/upload/metrics/angie/sum;
'stats_count' $p8s_value
path=/http/metric_zones/upload/metrics/angie/count;
'avg_size' $p8s_value
path=/http/metric_zones/upload/metrics/angie/avg_size;
}
server {
listen 80;
# Updating the metric
location ~ ^/upload/(.*)$ {
api /status/http/metric_zones/upload/metrics/angie/;
metric upload angie=$1 on=request;
}
# Target for metric scraping
location /prometheus/upload_metric/ {
prometheus upload_metric;
}
}
}
/upload/...:$ curl 127.0.0.1/upload/16384
$ curl 127.0.0.1/upload/64448
$ curl 127.0.0.1/upload/64
$ curl 127.0.0.1/upload/1028
$ curl 127.0.0.1/upload/1028
{
"stats": {
"64": 1,
"256": 1,
"1024": 1,
"4096": 3,
"16384": 4,
"+Inf": 5
},
"sum": 82952,
"count": 5,
"avg_size": 1077.9376
}
/prometheus/upload_metric/:# Angie Prometheus template "upload_metric"
# TYPE stats histogram
stats{le="64"} 1
stats{le="256"} 1
stats{le="1024"} 1
stats{le="4096"} 3
stats{le="16384"} 4
stats{le="+Inf"} 5
stats_sum 82952
stats_count 5
avg_size 1077.9376