Metric#

El módulo ngx_http_metric_module permite crear métricas arbitrarias calculadas en tiempo real. Estos valores de métricas se almacenan en memoria compartida y se muestran en tiempo real dentro de la rama de API /status/http/metric_zones/. Se admiten varios tipos de agregación de datos (contadores, histogramas, promedios móviles, etc.) con agrupación por claves arbitrarias.

Ejemplo de Configuración#

Conteo de solicitudes de API:

http {
    metric_zone api_requests:1m count;

    server {
        listen 80;

        location /api/ {
            allow 127.0.0.1;
            deny all;
            api /status/;

            metric api_requests $http_user_agent on=request;
        }
    }
}

Si se realiza una solicitud a /api/ con esta configuración:

$ curl 127.0.0.1/api/ --user-agent "Firefox"

La métrica api_requests se actualiza en tiempo real:

{
    "http": {
       "metric_zones": {
           "api_requests": {
               "discarded": 0,
               "metrics": {
                   "Firefox": 1
               }
           }
       }
    }
}

Directivas#

metric_zone#

Sintaxis

metric_zone nombre:tamaño [expire=on| off] [discard_key=nombre] modo [parámetros];

Por defecto

Contexto

http

Crea una zona de memoria compartida del tamaño especificado con el nombre dado para almacenar métricas. El nombre de la zona sirve como nodo en la rama /status/http/metric_zones/.

Parámetros:

  • expire=<on|off> — comportamiento cuando la zona está llena:

    • Si es on, las métricas más antiguas (por tiempo de actualización) se descartan para

      liberar memoria para las nuevas;

    • Si es off (por defecto) — las nuevas métricas entrantes se descartan,

      preservando las entradas existentes.

  • discard_key=<nombre> — define una métrica con la clave nombre

    donde se acumulan los valores de las métricas descartadas. Por defecto, no se crea tal métrica. La clave reservada no puede actualizarse manualmente.

  • modo — algoritmo de procesamiento de datos (ver la sección Modos de Operación);

  • parámetros — configuraciones adicionales para el modo seleccionado

    (por ejemplo, factor para average exp).

Ejemplo de uso:

metric_zone request_time:1m max;

En el árbol de API, la plantilla de zona de memoria compartida se ve de la siguiente manera:

{
    "discarded": 0,
    "metrics": {
        "key1": 123,
        "key2": 10.5,
    }
}

discarded

Número; el recuento de métricas descartadas en la zona de memoria compartida

metrics

Objeto; sus miembros son métricas con claves definidas y valores calculados

Nota

En una zona de 1 MB, con un tamaño de clave de 39 bytes y un modo de métrica única, se pueden almacenar aproximadamente 8.000 entradas de claves únicas.

metric_complex_zone#

Sintaxis

metric_complex_zone nombre:tamaño [expire=on| off] [discard_key=nombre] { ... }

Por defecto

Contexto

http

Define una métrica compleja — un conjunto de métricas con modos independientes. Cada línea en el cuerpo del bloque define un nombre de submétrica, un modo y parámetros opcionales del modo.

Ejemplo de uso:

metric_complex_zone requests:1m expire=on discard_key="old" {
    # nombre submétrica   modo          parámetros
    min_time              min;
    avg_time              average exp   factor=60;
    max_time              max;
    total                 count;
}

En el árbol de API, tal métrica compleja se ve de la siguiente manera:

{
    "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
        }
    }
}

discarded

Número; el recuento de métricas descartadas en la zona de memoria compartida

metrics

Objeto; sus miembros son métricas complejas con claves establecidas. Son objetos que contienen un conjunto de submétricas con valores calculados

metric#

Sintaxis

metric nombre clave=valor [on=request| response| end];

Por defecto

Contexto

http, server, location

Calcula el valor de la métrica para la zona de memoria compartida nombre especificada.

Parámetros:

  • clave — una cadena arbitraria (a menudo una variable) utilizada para agrupar valores.

    La longitud máxima es de 255 bytes. Si la clave es más larga, se truncará a 255 bytes y se agregará con puntos suspensivos ...;

  • valor — un número (puede ser una variable) procesado por el modo seleccionado.

    Si se omite, el valor predeterminado es 0. Si el parámetro no puede convertirse a un número, el valor predeterminado es 1;

  • on — un parámetro opcional que especifica cuándo se calcula la métrica:

    • Si es on=request, el cálculo ocurre cuando se recibe la solicitud;

    • Si es on=response, el cálculo ocurre durante la preparación de la respuesta;

    • Si es on=end (por defecto), el cálculo ocurre después de que se envía la respuesta.

Nota

En el caso de redirección interna, las métricas en la etapa on=request se calculan en el location original. Sin embargo, las métricas on=response y on=end se calcularán en el nuevo location.

Ejemplo de uso:

metric requests $http_user_agent=$request_time;

Nota

Las métricas con una clave vacía o un par clave=valor inválido se ignoran. Un valor omitido se trata como 0:

metric foo $bar;  # Equivalente a $bar=0

Esto es útil, por ejemplo, para el modo count, que ignora los valores numéricos y simplemente reacciona al hecho de que se actualizó una métrica.

Nota

Recuerde que las variables se evalúan en diferentes fases. Por ejemplo, es imposible usar $bytes_sent (bytes enviados al cliente) con on=request (cuando se recibe la solicitud).

Modos de Operación#

Lista de modos de operación de métricas disponibles:

  • count — contador;

  • gauge — medidor (incremento/decremento);

  • last — el último valor recibido;

  • min — valor mínimo;

  • max — valor máximo;

  • average exp — promedio móvil exponencial (EMA) (parámetro factor);

  • average mean — promedio sobre una ventana (parámetros window y count);

  • histogram — distribución en "cubos" (una lista de valores umbral).

count#

El contador aumenta su valor en 1 con cada actualización de métrica.

Valor por defecto — 0.

Nota

Cualquier actualización de métrica (con cualquier valor) aumenta monótonamente el contador en 1.

Ejemplos:

metric_zone count:1m count;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualizando la métrica:

$ 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

Valor esperado de la métrica en la API:

{
    "KEY": 4
}

gauge#

El gauge aumenta o disminuye su valor dependiendo del signo del número pasado. Un valor positivo aumenta el contador, mientras que un valor negativo lo disminuye. Un valor de 0 no cambia el contador.

Valor predeterminado — 0.

Ejemplos:

metric_zone gauge:1m gauge;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualización de la métrica:

$ curl 127.0.0.1/metric/

Valor esperado de la métrica en la API:

{
    "KEY": 0
}

Actualizaciones adicionales:

$ curl 127.0.0.1/metric/set/5
$ curl 127.0.0.1/metric/set/-5
$ curl 127.0.0.1/metric/set/8

Valor esperado de la métrica en la API:

{
    "KEY": 8
}

last#

Almacena el último valor recibido sin ninguna agregación. Si se omite value, se utiliza 0.

Ejemplos:

metric_zone last:1m last;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualización de la métrica:

$ curl 127.0.0.1/metric/

Valor esperado de la métrica en la API:

{
    "KEY": 0
}

Actualizaciones adicionales:

$ 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

Valor esperado de la métrica en la API:

{
   "KEY": -3.5
}

min#

Guarda el mínimo de dos valores — el valor almacenado actualmente y el nuevo.

Ejemplos:

metric_zone min:1m min;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualización de la métrica:

$ 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/

Valor esperado de la métrica en la API:

{
    "KEY": -512
}

max#

Guarda el máximo de dos valores — el valor almacenado actualmente y el nuevo.

Ejemplos:

metric_zone max:1m max;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualización de la métrica:

$ 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/

Valor esperado de la métrica en la API:

{
    "KEY": 42.999
}

average exp#

Calcula el valor promedio utilizando el algoritmo de suavizado exponencial.

Acepta un parámetro opcional factor=<número> — un coeficiente que determina cuánto influye el nuevo valor en el promedio. Se permiten valores enteros de 0 a 99. El valor predeterminado es 90.

Cuanto mayor sea el coeficiente, más peso tendrán los nuevos valores. Si especifica 90, el resultado será 90% del nuevo valor y 10% del promedio anterior.

Ejemplos:

metric_zone avg_exp:1m average exp factor=60;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualización de la métrica:

$ 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

Valor esperado de la métrica en la API:

{
    "KEY": 30.16
}

average mean#

Calcula la media aritmética. Acepta parámetros opcionales window=<off|tiempo> y count=<número>, que definen el intervalo de tiempo y el tamaño de la muestra para el promedio, respectivamente. Valores predeterminados: window=off (se utiliza toda la muestra) y count=10.

Nota

Por ejemplo, window=5s solo considerará eventos de los últimos 5 segundos. El parámetro window no puede ser 0. El parámetro count=número controla el tamaño de la muestra (valores en caché) para un cálculo de media más suave.

Ejemplos:

metric_zone avg_mean:1m average mean window=5s count=8;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualización de la métrica:

$ 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

Valor esperado de la métrica en la API:

{
    "KEY": 2.1
}

Si espera 5 segundos desde la última actualización, el valor esperado será:

{
    "KEY": 0
}

histogram#

Crea un conjunto de "buckets", incrementando el contador correspondiente si el nuevo valor no excede el umbral del bucket. Los parámetros se proporcionan como una lista de umbrales numéricos. Útil para analizar distribuciones, como tiempos de respuesta.

Los parámetros obligatorios son números — los valores de umbral de los buckets, listados en orden ascendente.

Nota

El valor de bucket inf o +Inf puede utilizarse para capturar todos los valores que excedan el bucket más alto especificado.

Ejemplos:

metric_zone hist:1m histogram 0.1 0.2 0.5 1 2 inf;

# Como parte de una métrica compleja:
#
# 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/;
    }
}

Actualización de la métrica:

$ curl 127.0.0.1/metric/set/0.25

Valor esperado de la métrica en la API:

{
    "KEY": {
        "0.1": 0,
        "0.2": 0,
        "0.5": 1,
        "1": 1,
        "2": 1,
        "inf": 1
    }
}

Actualizaciones adicionales:

$ curl 127.0.0.1/metric/set/2

Valor esperado de la métrica en la API:

{
    "KEY": {
        "0.1": 0,
        "0.2": 0,
        "0.5": 1,
        "1": 1,
        "2": 2,
        "inf": 2
    }
}

Actualización adicional:

$ curl 127.0.0.1/metric/set/1000

Valor esperado de la métrica en la API:

{
    "KEY": {
       "0.1": 0,
       "0.2": 0,
       "0.5": 1,
       "1": 1,
       "2": 2,
       "inf": 3
    }
}

Variables Integradas#

Se crean variables para cada métrica:

  • $metric_<nombre>

  • $metric_<nombre>_key

  • $metric_<nombre>_value

Para métricas complejas, se añade una variable adicional:

  • $metric_<nombre>_value_<métrica>

$metric_<nombre>#

Similar a la directiva metric, la variable setter $metric_<nombre> puede utilizarse para actualizar una métrica. El cálculo se produce durante la fase Rewrite, permitiendo el procesamiento de métricas desde el módulo njs, por ejemplo.

El valor utilizado para establecer la variable debe seguir la estructura clave=valor. Tanto la clave como el valor pueden consistir en texto, variables y combinaciones de ambos. La clave es una cadena arbitraria para agrupar valores. El valor es un número procesado por el modo seleccionado. Si se omite, el valor predeterminado es 0. Si el parámetro no puede convertirse en un número, el valor predeterminado es 1.

Ejemplo de uso:

http {
    metric_zone counter:1m count;

    # En este punto, se añade la variable $metric_counter

    server {
        listen 80;

        location /metric/ {
            set $metric_counter $http_user_agent;  # Equivalente a $http_user_agent=0
        }

        location /api/ {
            allow 127.0.0.1;
            deny all;
            api /status/http/metric_zones/counter/;
        }
    }
}

Cálculo de métricas utilizando el módulo njs:

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/;
    }
}

Archivo 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/')]);

    // Usando la variable setter $metric_requests
    r.variables.metric_requests = `google={Date.now() - start_time}`;
}

export default {js_request};

Después de varias peticiones a location /metric/, los valores podrían verse así:

{
    "discarded": 0,
    "metrics": {
        "google": {
            "min_time": 70,
            "max_time": 432,
            "total": 6
        }
    }
}

Nota

Después de establecer la variable, puede recuperar su valor; será igual al par clave=valor especificado.

Además, el valor almacenado en la variable $metric_<nombre>_key cambiará a la clave especificada.

$metric_<nombre>_key y $metric_<nombre>_value#

Las variables $metric_<nombre>_key y $metric_<nombre>_value definen la clave y el valor respectivamente. La actualización de la métrica se produce cuando se establece $metric_<nombre>_value, siempre que la clave en $metric_<nombre>_key ya haya sido definida.

Nota

Para métricas complejas, los valores de las submétricas en la variable $metric_<nombre>_value se unen utilizando un separador ", ".

Ejemplo de uso:

http {
    metric_zone gauge:1m gauge;

    # Aquí se añaden las variables $metric_gauge, $metric_gauge_key y $metric_gauge_value.

    metric_complex_zone complex:1m {
        hist histogram 1 2 3;
        avg  average exp;
    }

    # Aquí se añaden $metric_complex, $metric_complex_key y $metric_complex_value.

    server {
        listen 80;

        location /gauge/ {
            set $metric_gauge_key "foo";
            set $metric_gauge_value 1;

            # O: set $metric_gauge foo=1;

            return 200 "Actualizado con '$metric_gauge'\nValor='$metric_gauge_value'\n";
        }

        location /complex/ {
            set $metric_complex_key "foo";
            set $metric_complex_value 3;

            # O: set $metric_complex foo=3;

            return 200 "Actualizado con '$metric_complex'\nValor='$metric_complex_value'\n";
        }
    }
}

Con esta configuración, una petición a /gauge/ produce:

$ curl 127.0.0.1/gauge/
Actualizado con 'foo=1'
Valor='1'

Para /complex/:

$ curl 127.0.0.1/complex/
Actualizado con 'foo=3'
Valor='0 0 1, 3'

Nota

Si se asigna una cadena vacía a $metric_<nombre>_value, el valor se reconoce como 0. Si la cadena consiste en caracteres que no pueden convertirse en un número, se reconoce como 1.

El cálculo se produce solo después de que tanto $metric_<nombre>_key como $metric_<nombre>_value hayan sido establecidos.

En este caso, el valor almacenado en $metric_<nombre> se vuelve igual al nuevo par clave=valor.

El valor en $metric_<nombre>_key representa la última clave especificada mediante variables.

El valor en $metric_<nombre>_value representa el último valor calculado para la clave establecida en $metric_<nombre>_key.

$metric_<nombre>_value_<métrica>#

Para métricas complejas, el valor de una submétrica específica puede recuperarse utilizando la variable $metric_<nombre>_value_<métrica>, donde <métrica> es el nombre de la submétrica.

Ejemplo de uso:

http {
    metric_complex_zone foo:1m {
        count count;
        min   min;
        avg   average exp;
    }

    # Añade $metric_foo, $metric_foo_key, $metric_foo_value,
    # y $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;

            # O: set $metric_foo bar=9;

            return 200 "Actualizado con '$metric_foo'\nValores='$metric_foo_value'\nContador='$metric_foo_value_count'\n";
        }
    }
}

Con esta configuración, una petición a /foo/ produce:

$ curl 127.0.0.1/foo/
Actualizado con 'bar=9'
Valores='1, 9, 9'
Contador='1'

Ejemplos Adicionales#

Monitorización de Métodos HTTP#

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/;
    }
}

Respuesta:

{
    "GET": 65,
    "POST": 20,
    "PUT": 10,
    "DELETE": 5
}

Distribución del Tiempo de Respuesta del Upstream#

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/;
    }
}

Respuesta:

{
    "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
        }
    }
}

Conexiones Activas#

metric_zone active_connections:2m gauge;

server {
    listen 80;
    server_name site1.com;

    location / {
        # Incrementamos al conectar
        metric active_connections site1=1 on=request;

        # Decrementamos al finalizar
        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;
    }
}

Respuesta:

{
    "site1": 42,
    "site2": 17
}

Soporte de Prometheus#

Angie incluye un módulo integrado para mostrar métricas en formato Prometheus, que admite métricas personalizadas.

Como ejemplo de integración, considere la siguiente configuración:

http {
    # Creando la métrica "upload"
    metric_complex_zone upload:1m discard_key="other" {
        stats    histogram 64 256 1024 4096 16384 +Inf;
        sum      gauge;
        count    count;
        avg_size average exp;
    }

    # Describiendo la plantilla Prometheus para la métrica "upload"
    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;

        # Actualizando la métrica
        location ~ ^/upload/(.*)$ {
            api /status/http/metric_zones/upload/metrics/angie/;
            metric upload angie=$1 on=request;
        }

        # Destino para la recopilación de métricas
        location /prometheus/upload_metric/ {
            prometheus upload_metric;
        }
    }
}

Después de varias solicitudes a /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

Los valores de la métrica serán:

{
    "stats": {
        "64": 1,
        "256": 1,
        "1024": 1,
        "4096": 3,
        "16384": 4,
        "+Inf": 5
    },

    "sum": 82952,
    "count": 5,
    "avg_size": 1077.9376
}

En formato Prometheus, la métrica está disponible en /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