Acerca del lenguaje de consultas de Monitoring (MQL)

En esta página, se proporciona información general sobre el lenguaje de consulta de Monitoring (MQL), incluidos los siguientes temas:

Esta información se aplica si usas MQL desde la consola de Google Cloud o desde la API de Cloud Monitoring. Para obtener información sobre la estructura de las consultas de MQL, consulta Ejemplos.

Accesos directos para operaciones y funciones de tabla

Por lo general, las consultas constan de cadenas conectadas de operaciones de tabla conectadas por canalizaciones (|), cada una de las cuales comienza con el nombre de la operación de tabla seguida de una lista de expresiones. Las expresiones pueden contener llamadas a funciones que enumeran todos sus argumentos de forma explícita. Sin embargo, el lenguaje de consulta de Monitoring permite que las consultas se expresen mediante una serie de accesos directos.

En esta sección, se describen los accesos directos para las operaciones de tabla, mediante funciones como operaciones de tabla, y un acceso directo para las columnas de valor como argumentos de las funciones.

Para ver una lista completa, consulta Accesos directos de operaciones de tablas.

Accesos directos para operaciones de tabla

Cuando usas las operaciones fetch, group_by y filter, puedes omitir la operación de tabla explícita cuando los argumentos sean suficientes para determinar la operación deseada. Por ejemplo, la siguiente consulta:

gce_instance::compute.googleapis.com/instance/cpu/utilization

es equivalente a lo siguiente:

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization

Las siguientes operaciones de group_by son equivalentes:

         [zone], mean(val())
group_by [zone], mean(val())

Puedes omitir la palabra filter si escribes entre paréntesis la prueba de filtro. Por ejemplo, las siguientes dos operaciones filter son el equivalente:

       (instance_name =~ 'apache.*')
filter instance_name =~ 'apache.*'

Puedes combinar estos formularios de acceso directo en tus consultas. Por ejemplo, la siguiente consulta:

gce_instance::compute.googleapis.com/instance/cpu/utilization
| (instance_name =~ 'apache.*')
|  [zone], mean(val())

es equivalente a esta forma más explícita:

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| filter instance_name =~ 'apache.*'
| group_by [zone], mean(val())

Si deseas obtener más información sobre los accesos directos para operaciones de tabla, consulta Accesos para operaciones de tabla en la referencia de MQL.

Usa una función como una operación de tabla

Una operación de tabla suele comenzar con el nombre de esa operación. Sin embargo, MQL permite que una operación de tabla comience con un nombre de función en su lugar.

Puedes usar un nombre de función cuando la función nombrada sea realizar alguna transformación de las columnas de valores de la tabla de entrada. Este reemplazo es un acceso directo para las operaciones de tabla group_by, align o value, según el tipo de función cuyo nombre se proporcione.

El formato general es el siguiente:

|  FUNCTION_NAME ARG, ARG ... 

En la operación de tabla, la función toma las columnas de valores de la tabla de entrada como argumentos, seguidos de cualquier argumento para la función. Cuando se usa una función como una operación de tabla, debes especificar los argumentos en el formulario de operación de tabla, como una lista separada por comas, en lugar de hacerlo entre paréntesis (()) que se suelen usar con funciones.

La operación de tabla completa que se genera cuando se expande el acceso directo depende del tipo de función:

  • group_by: Si estás usando unfunción de agregación con ungroup_by operación que agrega todas las columnas de identificador de serie temporal (es decir, usa[] para agrupar), puedes usar la función como acceso directo. Por ejemplo:

    | distribution powers_of(1.1)

    es un acceso directo para

    | group_by [], distribution(val(0), powers_of(1.1))
  • align: Si usas una función de alineación como argumento para la operación align, puedes usar la función como un acceso directo. Por ejemplo:

    | delta

    es un acceso directo para

    | align delta()

    Del mismo modo,

    | rate 10m

    es un acceso directo para

    | align rate(10m)

    Ten en cuenta que las funciones de alineador toman la serie temporal de entrada como un argumento implícito, por lo que las columnas de valores no se proporcionan de forma explícita aquí.

  • value: Todas las demás funciones pueden actuar como accesos directos para la operación de tabla value. Por ejemplo:

    | mul 3.3

    es un acceso directo para

    | value mul(val(0), 3.3)

    Del mismo modo,

    | div

    es un acceso directo para

    | value div(val(0), val(1))

    Ten en cuenta que la combinación de teclas div una operación de tabla de entrada con dos columnas de valores y produce una operación de tabla con una columna de valores que es la proporción.

Acceso directo para funciones de columna de valor

Puedes usar .function como acceso directo para function(val()) si hay una sola columna de valor en la entrada o como un acceso directo para function(val(0), val(1)) si hay dos valores. columnas, etc.

El punto al principio significa "Llamar a la siguiente función, proporcionando la columna de valor de punto de entrada (o columnas) como argumentos para la función".

Por ejemplo, .mean es un acceso directo para mean(val()). Los siguientes son equivalentes:

group_by [zone], .mean
group_by [zone], mean(val())

Si la tabla de entrada tiene varias columnas de valores, cada columna se convierte en un argumento para la función en este acceso directo. Por ejemplo, si la tabla de entrada tiene dos columnas de valores, entonces

.div

es un acceso directo para

div(val(0), val(1))

Con este acceso directo, puedes proporcionar argumentos que no hagan referencia a las columnas de valores. Los argumentos adicionales se proporcionan después de los argumentos de columna de valor. Por ejemplo, si la tabla de entrada tiene una columna de valores, entonces

.div(3)

es equivalente a

div(val(0), 3)

Variaciones en fetch

Por lo general, la operación fetch muestra una tabla de series temporales llamada por un par de tipos de métricas y recursos supervisados. Por ejemplo:

fetch gce_instance :: compute.googleapis.com/instance/cpu/utilization

Si la métrica se aplica solo a un tipo de recurso supervisado, puedes omitirlo de la consulta. La siguiente consulta es equivalente a la consulta anterior, porque la métrica de uso de CPU solo se aplica a los recursos supervisados gce_instance:

fetch compute.googleapis.com/instance/cpu/utilization

La operación fetch solo puede especificar un tipo de recurso supervisado, con la métrica especificada en operaciones posteriores metric. Por ejemplo, este ejemplo es equivalente a los ejemplos de fetch anteriores:

fetch gce_instance
| metric metric compute.googleapis.com/instance/cpu/utilization

Dividir la fetch de esta manera puede ser útil cuando deseas recuperar dos métricas diferentes para el mismo recurso supervisado. Por ejemplo, la siguiente consulta calcula la cantidad de paquetes por segundo de CPU consumidos:

fetch gce_instance
| {
    metric compute.googleapis.com/instance/network/received_packets_count ;
    metric compute.googleapis.com/instance/cpu/usage_time
  }
| ratio

Dividir la fetch también te permite aplicar el filtrado solo a las etiquetas del recurso supervisado:

fetch gce_instance
| filter resource.zone =~ "asia.*"
| {
    metric compute.googleapis.com/instance/network/received_packets_count ;
    metric compute.googleapis.com/instance/cpu/usage_time
  }
| ratio

Un fetch que nombra solo un tipo de recurso supervisado debe estar seguido de una operación metric, tal vez con operaciones filter intermedias.

Consultas de formato estricto

Una consulta estricta es una que no tiene ninguno de los accesos directos o valores implícitos que se usan en consultas concisas. Las consultas estrictas tienen las siguientes características:

  • Se reemplazan todos los accesos directos.
  • Todos los argumentos implícitos se hacen explícitos.
  • Las columnas se denominan con nombres completos.
  • Las columnas nuevas reciben nombres explícitos.
  • Cualquier operación de alineación proporcionada de forma implícita se proporciona de forma explícita.

El uso de la forma estricta hace que la consulta sea más resistente a los cambios en la estructura de las tablas de entrada y puede dejar en claro lo que hace la consulta. Agregar una consulta en formato estricto no hace que la consulta sea más eficiente.

Cuando guardas una consulta de un gráfico, esta se convierte en un formato estricto. En el cuadro de diálogo de confirmación de la operación de guardado, se muestra el formato estricto.

Las consultas concisas para las políticas de alertas no se convierten en una forma estricta. Las consultas para las políticas de alertas se almacenan a medida que las proporcionas; puedes usar una forma concisa o estricta.

Con accesos directos y formas estrictas disponibles, puedes encontrar consultas de MQL equivalentes que se ven muy diferentes entre sí. Por ejemplo, en la siguiente consulta, que calcula la cantidad de paquetes recibidos por segundo de CPU consumida, se usan muchos accesos directos:

gce_instance
| (zone =~ ".*-a")
| {
    compute.googleapis.com/instance/network/received_packets_count ;
    compute.googleapis.com/instance/cpu/usage_time
  }
| join
| div

Cuando guardas esta consulta en un gráfico o como parte de una política de alertas, el resultado es una consulta de formulario estricta. Sin embargo, el formato estricto puede ser bastante diferente, como se muestra en el siguiente ejemplo:

fetch gce_instance
| filter (resource.zone =~ '.*-a')
| { t_0:
      metric 'compute.googleapis.com/instance/network/received_packets_count'
      | align delta() ;
    t_1:
      metric 'compute.googleapis.com/instance/cpu/usage_time'
      | align delta() }
| join
| value [v_0: div(t_0.value.received_packets_count, t_1.value.usage_time)]

Cuando editas la definición guardada del gráfico, el editor de código muestra la forma estricta.

Coincidencia con la columna resource.project_id

Los proyectos de Google Cloud tienen un nombre visible, que aparece en los menús, pero no identifica de forma única el proyecto. El nombre visible de un proyecto podría ser “Supervisión de demostración”.

Los proyectos también tienen dos campos que actúan como identificadores:

  • ID del proyecto: un identificador de string único. A menudo, esto se basa en el nombre visible. Los ID de proyecto se configuran cuando se crea el proyecto, por lo general, cuando se concatenan los elementos del nombre del proyecto y, posiblemente, se agregan dígitos al final, si es necesario para que sea único. Un ID del proyecto podría tener el formato “monitoring-demo” o “monitoring-demo-2349”. A veces, el ID del proyecto se denomina nombre del proyecto.
  • Número de proyecto: un identificador numérico único.

Cada tipo de recurso supervisado incluye una etiqueta project_id, con una representación de string del número de proyecto que posee el recurso y los datos sobre ese recurso.

En las consultas de MQL, te refieres a esta etiqueta como resource.project_id. La etiqueta resource.project_id tiene el número de proyecto en formato de texto como valor, pero MQL convierte ese valor al ID del proyecto en ciertas situaciones.

En los siguientes casos, MQL trata el valor de la etiqueta resource.project_id como el ID del proyecto en lugar del número del proyecto:

  • La leyenda de un gráfico muestra el ID del proyecto en lugar del número del proyecto para el valor de la etiqueta resource.project_id.

  • Las comparaciones de igualdad del valor de resource.project_id con un literal de string reconocen el número y el ID del proyecto. Por ejemplo, los siguientes resultados son verdaderos para los recursos que son propiedad de este proyecto:

    • resource.project_id == "monitoring-demo"
    • resource.project_id == "530310927541"

    Este caso se aplica a los operadores == y !=, y para sus formas de funciones, eq() y ne().

  • Una coincidencia de expresión regular en la etiqueta resource.project_id funciona de manera correcta con el número o el ID del proyecto. Por ejemplo, las siguientes expresiones muestran true para los recursos que son propiedad de este proyecto:

    • resource.project_id =~ "monitoring-.*"
    • resource.project_id =~ ".*27541"

    Este caso se aplica a los operadores =~ y !~, y para el formulario de función, re_full_match.

En todos los demás casos, se usa el valor real de la etiqueta resource.project_id. Por ejemplo, concatenate("project-", resource.project_id) da como resultado el valor project-530310927541 y no project-monitoring-demo.

Proporción y el “efecto perimetral”

En general, es mejor calcular las proporciones según las series temporales recopiladas para un solo tipo de métrica mediante el uso de valores de etiquetas. Una proporción calculada en dos tipos de métricas diferentes está sujeta a anomalías debido a diferentes períodos de muestreo y ventanas de alineación.

Por ejemplo, supongamos que tienes dos tipos de métricas, un recuento total de RPC y un recuento de errores de RPC, y deseas calcular la proporción de las RPC del recuento de errores sobre el total de RPC. Las RPC con errores se cuentan en las series temporales de ambos tipos de métricas. Por lo tanto, existe la posibilidad de que, cuando alineas las series temporales, una RPC con éxito no aparezca en el mismo intervalo de alineación para ambas series temporales. Esta diferencia puede ocurrir por varias razones, incluidas las siguientes:

  • Debido a que hay dos series temporales diferentes que registran el mismo evento, hay dos valores de contador subyacentes que implementan la colección y no se actualizan de forma atómica.
  • Las tasas de muestreo pueden variar. Cuando las series temporales se alinean con un período común, los recuentos de un solo evento pueden aparecer en intervalos de alineación adyacentes en las series temporales para las diferentes métricas.

La diferencia en la cantidad de valores en los intervalos de alineación correspondientes puede generar valores de proporción error/total sin sentido, como 1/0 o 2/1.

Las proporciones de números más grandes tienen menos probabilidades de dar como resultado valores sin sentido. Puedes obtener números más grandes mediante la agregación, ya sea mediante una ventana de alineación más larga que el período de muestreo o mediante la agrupación de datos para ciertas etiquetas. Estas técnicas minimizan el efecto de las pequeñas diferencias en la cantidad de puntos en un intervalo determinado. Es decir, una disparidad de dos puntos es más significativa cuando la cantidad esperada de puntos en un intervalo es 3 que cuando el número esperado es 300.

Si usas tipos de métricas integradas, es posible que no tengas más opción que calcular las proporciones entre los tipos de métricas para obtener el valor que necesitas.

Si diseñas métricas personalizadas que pueden contar lo mismo, como las RPC que muestran el estado del error, en dos métricas diferentes, considera una sola métrica, que incluye cada recuento solo una vez. Por ejemplo, supongamos que cuentas las RPC y deseas realizar un seguimiento de la proporción de RPC con errores a todas las RPC. Si quieres resolver este problema, crea un solo tipo de métrica para contar las RPC y usa una etiqueta a fin de registrar el estado de la invocación, incluido el estado “OK”. Luego, cada valor de estado, error u "OK", se registra mediante la actualización de un solo contador para ese caso.

Formatos de fecha de MQL

MQL ahora admite una cantidad limitada de formatos de fecha. En las consultas de MQL, las fechas se expresan como una de las siguientes opciones:

  • d'BASE_STRING'
  • D'BASE_STRING'

BASE_STRING es una string con el formato 2010/06/23-19:32:15-07:00. El primer guión (-), que separa la fecha y hora, se puede reemplazar por un espacio. En el componente de tiempo, se pueden descartar partes del tiempo de reloj (19:32:15) o el especificador de zona horaria (-07:00).

Los siguientes ejemplos son fechas válidas en las consultas de MQL:

  • d'2010/06/23-19:32:15-07:00'
  • d'2010/06/23 19:32:15-07:00'
  • d'2010/06/23 19:32:15'
  • D'2010/06/23 19:32'
  • d'2010/06/23-19'
  • D'2010/06/23 -07:00'

En la siguiente tabla, se muestra la gramática de BASE_STRING:

Estructura Significado
%Y/%m/%d Fecha
%Y/%m/%d %H
%Y/%m/%d-%H
DATE, HOUR
%Y/%m/%d %H:%M
%Y/%m/%d-%H:%M
Fecha, hora, minuto
%Y/%m/%d %H:%M:%S
%Y/%m/%d-%H:%M:%S
Fecha, hora, minuto, segundo
%Y/%m/%d %H:%M:%E*S
%Y/%m/%d-%H:%M:%E*S
Fecha, hora, minuto, segundo fraccionario
%Y/%m/%d %Ez Fecha con zona horaria
%Y/%m/%d %H%Ez
%Y/%m/%d-%H%Ez
Fecha, hora, con zona horaria
%Y/%m/%d %H:%M%Ez
%Y/%m/%d-%H:%M%Ez
Fecha, hora, minuto con zona horaria
%Y/%m/%d %H:%M:%S%Ez
%Y/%m/%d-%H:%M:%S%Ez
Fecha, hora, minuto y segundo con zona horaria
%Y/%m/%d %H:%M:%E*S%Ez
%Y/%m/%d-%H:%M:%E*S%Ez
Fecha, hora, minuto y segundo fraccionario con zona horaria

Longitud y complejidad de las consultas

Las consultas del lenguaje de consulta de Monitoring pueden ser largas y complejas, pero no sin límites.

  • Un texto de consulta, codificado como UTF-8, está limitado a 10,000 bytes.
  • Una consulta tiene un límite de 2,000 construcciones de idiomas; es decir, la complejidad de AST está limitada a 2,000 nodos.

Un árbol de sintaxis abstracta, o AST, es una representación del código fuente, en este caso, la string de consulta MQL, en la que en el árbol se mapean estructuras sintácticas en el código.

Macros de MQL

MQL incluye una utilidad de definición de macros. Puedes usar los macros de MQL para reemplazar las operaciones repetidas, hacer que las consultas complejas sean más legibles y facilitar el desarrollo de consultas. Puedes definir macros para operaciones de tabla y funciones.

Las definiciones de macro comienzan con la palabra clave def.

Cuando conviertes una consulta en formato estricto, las invocaciones de macro se reemplazan por su texto correspondiente y se quitan las definiciones.

Cuando guardas una consulta de gráfico que incluye macros, la consulta se convierte a un formato estricto, de modo que no se conserven las macro. Cuando guardas una consulta para una condición en una política de alertas, la consulta no se convierte a un formato estricto, por lo que se conservan las macros.

Macros para operaciones de tabla

Puedes escribir macros para realizar operaciones de tabla nuevas. La sintaxis general se ve de la siguiente manera:

def MACRO_NAME [MACRO_PARAMETER[, MACRO_PARAMETER]] = MACRO_BODY ;

Para invocar la macro, usa la siguiente sintaxis:

@MACRO_NAME [MACRO_ARG [, MACRO_ARG]]

Por ejemplo, supongamos que usas la siguiente consulta para recuperar los datos de uso de CPU:

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| every 1m
| group_by [zone], mean(val())

La primera línea se puede reemplazar por la siguiente macro:

def my_fetch = fetch gce_instance::compute.googleapis.com/instance/cpu/utilization ;

Para invocar la macro en la consulta, reemplaza el fetch original de la siguiente manera:

def my_fetch = fetch gce_instance::compute.googleapis.com/instance/cpu/utilization ;

@my_fetch
| every 1m
| group_by [zone], mean(val())

Puedes reemplazar la segunda y tercera línea por macros que tomen argumentos. La definición de la macro muestra los parámetros de la macro y, en el cuerpo de la macro, se hace referencia a los parámetros de la macro como $MACRO_PARAMETER. Por ejemplo, puedes definir las siguientes macro:

def my_every time_arg = every $time_arg ;

def my_group label, aggr = group_by [$label], $aggr ;

Para invocar estas macro y proporcionar los argumentos, especifica los argumentos en una lista delimitada por comas en las invocaciones de macro. A continuación, se muestra la consulta con todas las macros definidas y sus invocaciones:

def my_fetch = fetch gce_instance::compute.googleapis.com/instance/cpu/utilization ;
def my_every time_arg = every $time_arg ;
def my_group label, aggr = group_by [$label], $aggr ;

{@my_fetch}
| @my_every 1m
| @my_group zone, mean(val())

Las macro no se conservan cuando la consulta se convierte en forma estricta. Por ejemplo, la forma estricta de la consulta anterior se ve así:

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| align mean_aligner()
| every 1m
| group_by [resource.zone],
           [value_utilization_mean: mean(value.utilization)]

Macros para funciones

Para las funciones de MQL, especifica cualquier parámetro en una lista delimitada por comas entre paréntesis. Los paréntesis distinguen una macro de función de una macro de operación de tabla. Los paréntesis deben aparecer en la invocación, incluso si no hay argumentos. Las macros no se conservan cuando la consulta se convierte en forma estricta.

def MACRO_NAME([MACRO_PARAMETER [, MACRO_PARAMETER]]) = MACRO_BODY ;

Por ejemplo, la siguiente consulta recupera tablas para dos métricas, combina las dos tablas en una con dos columnas de valores y calcula la proporción de bytes recibidos con bytes totales para una columna llamada received_percent:

{
  fetch k8s_pod :: kubernetes.io/pod/network/received_bytes_count ;
  fetch k8s_pod :: kubernetes.io/pod/network/sent_bytes_count
}
| join
| value [received_percent: val(0) * 100 / (val(0) + val(1))]

Puedes reemplazar el cálculo received_percent por una macro como la del siguiente ejemplo:

def recd_percent(recd, sent) = $recd * 100 / ($recd + $sent) ;

Para invocar una macro de función, usa la siguiente sintaxis:

@MACRO_NAME([MACRO_ARG[, MACRO_ARG]])

Cuando se invoca una macro de función sin argumentos, debes especificar los paréntesis vacíos para distinguir la invocación de la invocación de una macro de operación de tabla.

En el siguiente ejemplo, se muestra la consulta anterior con una macro para el cálculo de la proporción:

def recd_percent(recd, sent) = $recd * 100 / ($recd + $sent) ;

{
  fetch k8s_pod :: kubernetes.io/pod/network/received_bytes_count ;
  fetch k8s_pod :: kubernetes.io/pod/network/sent_bytes_count
}
| join
| value [received_percent: @recd_percent(val(0), val(1))]

Funciones de macro

Las macro de MQL son elementos sintácticos, a diferencia de los textos, como las macro que se usan en el preprocesador C. Esta distinción significa que un cuerpo de macro MQL siempre debe ser una expresión sintácticamente válida. Es posible que no sea semánticamente válido, lo que también depende de los argumentos de la macro y de la ubicación donde la macro se expande.

Debido a que las macros de MQL son sintácticas, hay muy pocas restricciones sobre el tipo de expresión a la que se pueden expandir. Las macros sintácticas son otra forma de manipular el árbol de sintaxis abstracta. En los siguientes ejemplos, se muestran algunas de las acciones que puedes realizar con las macros sintácticas:

# Abbreviating a column name.
def my_col() = instance_name;

# Map-valued macro.
def my_map(c) = [$c, @my_col()];

# Abbreviating a string.
def my_zone() = 'us-central.*';

# Abbreviating a filter expression.
def my_filter(f) = zone =~ @my_zone() && $f;

MQL también admite la concatenación literal de strings. Esta característica puede ser muy útil cuando se escriben consultas que incluyen nombres de métricas largos. Cuando un literal de string y un argumento de macro, que también debe ser un literal de string, aparecen uno al lado del otro en el cuerpo de la macro, la expansión de macro los concatena en un solo literal de string.

En el siguiente ejemplo, gce_instance es un elemento léxico BARE_NAME. Se promueve de forma automática a un literal de string, lo que es útil para compilar nombres de tablas:

# Builds a table name in domain 'd' with the suffix 'm'.
def my_table(d, m) = gce_instance::$d '/instance/' $m;

# Table name under the given domain.
def my_compute_table(m) = @my_table('compute.googleapis.com', $m);

Debido a todo lo explicado, la siguiente consulta usa todas las macros definidas con anterioridad:

fetch @my_compute_table('cpu/utilization')
| filter @my_filter(instance_name =~ 'gke.*')
| group_by @my_map(zone)

Ten en cuenta que los argumentos de macro también pueden ser expresiones arbitrarias, siempre que sean sintácticamente correctos. Por ejemplo, la macro my_filter puede tomar una expresión booleana como instance_name =~ 'gke.*' como su primer argumento.

Abreviar las operaciones de tabla también puede ser muy útil, como se muestra en la siguiente consulta:

# Calculate the ratio between compute metrics 'm1' and 'm2'.
def my_compute_ratio m1, m2 =
  { fetch @my_compute_table($m1); fetch @my_compute_table($m2) }
  | join | div;

# Use the table op macro to calculate the ratio between CPU utilization and
# the number of reserved cores per zone.
@my_compute_ratio 'cpu/utilization', 'cpu/reserved_cores' | group_by [zone]

Por último, las macro de función se pueden comportar como las funciones normales. Es decir, permiten la promoción de funciones en las que la columna de valores o columnas de la tabla de entrada se convierten en los primeros argumentos en la macro. En el siguiente ejemplo, se muestra una variante de la consulta anterior que usa una macro de función:

# Simple arithmetic macro.
def my_add_two(x) = $x + 2;

# Similar to previous query, but now using the new arithmetic macro with
# function argument promotion.
fetch @my_compute_table('cpu/utilization')
| filter @my_filter(instance_name =~ 'gke.*')
| group_by @my_map(zone), [.sum.@my_add_two]

Limitaciones

La función de macro de MQL no admite lo siguiente:

  • Anidación de definiciones de macro: no puedes definir una macro en el cuerpo de otra macro.
  • Macros definidas de forma recurrente. Ningún cuerpo de macro puede hacer referencia a cualquier macro, incluida ella, que aún no esté definida por completo.
  • Uso de funciones definidas por macro como operaciones de tabla
  • Uso de argumentos macro como nombres de funciones o de operaciones de tabla.
  • Conservación de macros cuando la consulta se convierte en forma estricta. Las invocaciones de la macro se reemplazan por las expresiones correspondientes y se quitan las definiciones de macro.