Exemples de requêtes MQL

Ce document présente le langage MQL (Monitoring Query Language) à l'aide d'exemples. Cependant, il n'essaie pas de couvrir tous les aspects du langage. MQL est documenté de manière exhaustive dans la documentation de référence sur le langage de requête Monitoring.

Pour obtenir des informations sur les règles d'alerte basées sur MQL, consultez la page Règles d'alerte avec MQL.

Vous pouvez écrire une requête particulière sous de nombreuses formes. Le langage est flexible, et de nombreux raccourcis sont disponibles une fois que vous vous êtes familiarisé avec la syntaxe. Pour en savoir plus, consultez la section Requêtes de format strict.

Avant de commencer

Pour accéder à l'éditeur de code lorsque vous utilisez l'Explorateur de métriques, procédez comme suit:

  1. Dans le panneau de navigation de la console Google Cloud, sélectionnez Surveillance, puis  Explorateur de métriques :

    Accéder à l'Explorateur de métriques

  2. Dans la barre d'outils du volet de création de requêtes, sélectionnez le bouton nommé  MQL ou  PromQL.
  3. Vérifiez que MQL est sélectionné dans le bouton d'activation Langage. Le bouton de langage se trouve dans la barre d'outils qui vous permet de mettre en forme votre requête.

Pour exécuter une requête, collez-la dans l'éditeur, puis cliquez sur Exécuter la requête. Pour en savoir plus sur cet éditeur, consultez Utiliser l'éditeur de code pour MQL.

Une certaine connaissance des concepts de Cloud Monitoring, y compris des types de métriques, des types de ressources surveillées et des séries temporelles, est utile. Pour obtenir une présentation de ces concepts, consultez la page Métriques, séries temporelles et ressources.

Modèle de données

Les requêtes MQL récupèrent et manipulent les données de la base de données de séries temporelles Cloud Monitoring. Cette section présente certains concepts et termes associés à cette base de données. Pour en savoir plus, consultez la section Modèle de données dans la documentation de référence.

Chaque série temporelle provient d'un seul type de ressource surveillée, et chaque série temporelle collecte des données d'un type de métrique. Un descripteur de ressource surveillée définit un type de ressource surveillée. De même, un descripteur de la métrique définit un type de métrique. Par exemple, le type de ressource peut être gce_instance, une machine virtuelle (VM) Compute Engine, et le type de métrique peut être compute.googleapis.com/instance/cpu/utilization, soit l'utilisation du processeur de la VM Compute Engine.

Ces descripteurs spécifient également un ensemble de libellés permettant de collecter des informations sur d'autres attributs du type de ressource ou de métrique. Par exemple, les ressources ont généralement un libellé zone, qui permet d'enregistrer leur emplacement géographique.

Une série temporelle unique est créée pour chaque combinaison de valeurs pour les libellés de la paire d'un descripteur de métrique et d'un descripteur de ressource surveillée.

Vous trouverez les libellés disponibles pour les types de ressources dans la liste des ressources surveillées (par exemple, gce_instance). Pour trouver les libellés des types de métriques, consultez la liste des métriques. Par exemple, consultez la section Métriques de Compute Engine.

La base de données Cloud Monitoring stocke les séries temporelles d'une métrique et d'un type de ressource particuliers dans une seule table. Le type de métrique et le type de ressource servent d'identifiant pour la table. La requête MQL ci-dessous extrait la table des séries temporelles enregistrant l'utilisation du processeur pour les instances Compute Engine :

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

La table contient une série temporelle pour chaque combinaison unique de valeurs de métrique et de libellé de ressource.

Les requêtes MQL récupèrent les données de séries temporelles de ces tables et les transforment en tables de sortie. Ces tables de sortie peuvent être transmises à d'autres opérations. Par exemple, vous pouvez isoler les séries temporelles écrites par les ressources d'une zone ou d'un ensemble de zones spécifique en transmettant la table récupérée en tant qu'entrée à une opération filter :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| filter zone =~ 'us-central.*'

La requête précédente génère une table qui ne contient que les séries temporelles des ressources d'une zone commençant par us-central :

Les requêtes MQL sont structurées pour transmettre le résultat d'une opération en tant qu'entrée à l'opération suivante. Cette approche basée sur les tables vous permet d'associer des opérations pour manipuler ces données par le biais du filtrage, de la sélection et d'autres opérations de base de données courantes telles que les jointures internes et externes. Vous pouvez également exécuter diverses fonctions sur les données des séries temporelles lorsque celles-ci sont transmises d'une opération à une autre.

Les opérations et les fonctions disponibles dans le langage MQL sont entièrement décrites dans la documentation de référence sur le langage MQL.

Structure d'une requête

Une requête est composée d'une ou de plusieurs operations. Les opérations sont liées ou canalisées, de sorte que la sortie d'une opération soit l'entrée de la suivante. Par conséquent, le résultat d'une requête dépend de l'ordre des opérations. Voici quelques exemples de ce que vous pouvez faire :

  • Lancer une requête avec une opération fetch ou une autre opération de sélection
  • Créer une requête avec plusieurs opérations canalisées
  • Sélectionnez un sous-ensemble d'informations avec les opérations filter.
  • Agréger les informations associées avec les opérations group_by
  • Examiner les anomalies avec les opérations top et bottom
  • Combiner plusieurs requêtes avec les opérations { ; } et join
  • Utiliser l'opération et les fonctions value pour calculer des ratios et d'autres valeurs

Toutes les requêtes n'utilisent pas toutes ces options.

Ces exemples ne présentent qu'une partie des opérations et des fonctions disponibles. Pour en savoir plus sur la structure des requêtes MQL, consultez la section Structure des requêtes dans la documentation de référence.

Ces exemples ne spécifient pas deux choses que vous pouvez vous attendre à voir : les périodes et l'alignement. Les sections suivantes expliquent pourquoi.

Périodes

Lorsque vous utilisez l'éditeur de code, les paramètres du graphique définissent la période des requêtes. Par défaut, la période du graphique est définie sur une heure.

Pour modifier la période du graphique, utilisez le sélecteur de période. Par exemple, si vous souhaitez afficher les données de la semaine passée, sélectionnez La semaine dernière dans le sélecteur de période. Vous pouvez également spécifier une heure de début et de fin, ou une heure à laquelle afficher les résultats.

Pour en savoir plus sur les plages de temps dans l'éditeur de code, consultez Plages de temps, graphiques et éditeur de code.

Alignement

De nombreuses opérations utilisées dans ces exemples, telles que les opérations join et group_by, dépendent de tous les points de série temporelle d'une table qui se produisent à intervalles réguliers. L'action d'aligner tous les points à des horodatages réguliers est appelée alignment. En général, l'alignement est effectué implicitement, et aucun des exemples présentés ici ne le montre.

MQL aligne automatiquement les tables pour les opérations join et group_by en cas de besoin, mais MQL vous permet également d'effectuer l'alignement explicitement.

  • Pour obtenir des informations générales sur le concept d'alignement, consultez la section Alignement : agrégation au sein d'une série.

  • Pour plus d'informations sur l'alignement dans le langage MQL, consultez la section Alignement dans la documentation de référence. L'alignement peut être explicitement contrôlé à l'aide des opérations align et every.

Extraire et filtrer des données

Les requêtes MQL commencent par la récupération, la sélection ou le filtrage des données. Cette section illustre la récupération et le filtrage de base avec MQL.

Récupérer des données de séries temporelles

Une requête commence toujours par une opération fetch, qui récupère des séries temporelles à partir de Cloud Monitoring.

La requête la plus simple consiste en une seule opération fetch et un argument qui identifie les séries temporelles à extraire, comme suit :

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

L'argument comprend un type de ressource surveillée (gce_instance), une paire de signes deux-points (::) et un type de métrique (compute.googleapis.com/instance/cpu/utilization).

Cette requête récupère les séries temporelles écrites par les instances Compute Engine pour le type de métrique compute.googleapis.com/instance/cpu/utilization, qui enregistre l'utilisation du processeur par ces instances.

Si vous exécutez la requête à partir de l'éditeur de code de l'explorateur de métriques, vous obtenez un graphique affichant chacune des séries temporelles demandées:

Le graphique montre les données d'utilisation du processeur pour les instances Compute Engine.

Chacune des séries temporelles demandées est affichée sous forme de ligne dans le graphique. Chaque série temporelle inclut une liste de valeurs horodatées issues de la métrique d'utilisation du processeur pour une instance de VM de ce projet.

Dans l'espace de stockage backend utilisé par Cloud Monitoring, les séries temporelles sont stockées dans des tables. L'opération fetch organise dans une table la série temporelle pour les types de ressources surveillées et de métriques spécifiés, puis la renvoie. Les données renvoyées sont affichées dans le graphique.

L'opération fetch est décrite, ainsi que ses arguments, sur la page de référence sur fetch. Pour en savoir plus sur les données générées par les opérations, consultez les pages de référence sur les séries temporelles et les tables.

Filtrer les opérations

Les requêtes consistent généralement en une combinaison de plusieurs opérations. La combinaison la plus simple consiste à canaliser la sortie d'une opération vers l'entrée de la suivante en utilisant l'opérateur de barre verticale, |. L'exemple suivant illustre l'utilisation d'une barre verticale pour fournir en entrée la table dans une opération de filtrage :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| filter instance_name =~ 'gke.*'

Cette requête redirige la table, renvoyée par l'opération fetch décrite dans l'exemple précédent, en une opération filter qui prend comme expression une valeur booléenne. Dans cet exemple, l'expression signifie que "instance_name commence par gke".

L'opération filter prend la table d'entrée, supprime les séries temporelles pour laquelle le filtre est faux et génère la table obtenue. La capture d'écran suivante montre le graphique obtenu :

Le graphique affiche les résultats filtrés pour "gke".

Si aucun nom d'instance ne commence par gke, modifiez le filtre avant d'essayer cette requête. Par exemple, si vous avez des instances de VM comportant apache au début de leur nom, utilisez le filtre suivant :

 | filter instance_name =~ 'apache.*'

L'expression filter est évaluée une fois pour chaque série temporelle d'entrée. Si l'expression renvoie true, cette série temporelle est incluse dans la sortie. Dans cet exemple, l'expression de filtre procède à une mise en correspondance d'expression régulière, =~, sur le libellé instance_name de chaque série temporelle. Si la valeur du libellé correspond à l'expression régulière 'gke.*', la série temporelle est incluse dans la sortie. Dans le cas contraire, elle est supprimée de la sortie.

Pour plus d'informations sur le filtrage, consultez la page de référence sur filter. Le prédicat filter peut être n'importe quelle expression arbitraire qui renvoie une valeur booléenne. Pour en savoir plus, consultez la section Expressions.

Regrouper et agréger

Le regroupement vous permet de regrouper des séries temporelles en fonction de dimensions spécifiques. L'agrégation combine toutes les séries temporelles d'un groupe en une seule série temporelle de sortie.

La requête suivante filtre la sortie de l'opération fetch initiale pour ne conserver que les séries temporelles des ressources d'une zone commençant par us-central. Elle regroupe ensuite les séries temporelles par zone et les combine à l'aide de l'agrégation mean.

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

La table résultant de l'opération group_by comporte une série temporelle par zone. La capture d'écran suivante montre le graphique obtenu :

Graphique présentant une extraction filtrée regroupée par zone.

L'opération group_by prend deux arguments, séparés par une virgule (,). Ces arguments déterminent le comportement de regroupement précis. Dans cet exemple, group_by [zone], mean(val()), les arguments fonctionnent comme suit :

  • Le premier argument, [zone], est une expression map qui détermine le regroupement des séries temporelles. Dans cet exemple, elle spécifie les étiquettes à utiliser pour le regroupement. L'étape de regroupement collecte toutes les séries temporelles d'entrée ayant les mêmes valeurs zone de sortie dans un groupe. Dans cet exemple, l'expression collecte la série temporelle à partir des VM Compute Engine dans une zone.

    La série temporelle de sortie ne comporte qu'un libellé zone, la valeur étant copiée à partir de la série temporelle d'entrée dans le groupe. Les autres libellés des séries temporelles d'entrée sont supprimés de la série temporelle de sortie.

    L'expression de mappage peut faire bien plus que de répertorier des libellés. Pour en savoir plus, consultez la page de référence sur map.

  • Le deuxième argument, mean(val()), détermine comment les séries temporelles de chaque groupe sont combinées, ou aggregated, en une série temporelle de sortie. Chaque point de la série temporelle de sortie d'un groupe est le résultat de l'agrégation des points avec le même horodatage provenant de toutes les séries temporelles d'entrée du groupe.

    La fonction d'agrégation, mean dans cet exemple, détermine la valeur agrégée. La fonction val() renvoie les points à agréger. La fonction d'agrégation est appliquée à ces points. Dans cet exemple, vous obtenez la moyenne de l'utilisation du processeur des machines virtuelles de la zone à chaque point de sortie.

    L'expression mean(val()) est un exemple d'expression d'agrégation.

L'opération group_by combine toujours regroupement et agrégation. Si vous spécifiez un regroupement, mais omettez l'argument d'agrégation, group_by utilise une agrégation par défaut, aggregate(val()), qui sélectionne une fonction appropriée pour le type de données. Consultez la section sur aggregate pour obtenir la liste des fonctions d'agrégation par défaut.

Utiliser group_by avec une métrique basée sur les journaux

Supposons que vous ayez créé une métrique basée sur les journaux de distribution pour extraire le nombre de points de données traités à partir d'un ensemble d'entrées longues comprenant des chaînes telles que:

... entry ID 1 ... Processed data points 1000 ...
... entry ID 2 ... Processed data points 1500 ...
... entry ID 3 ... Processed data points 1000 ...
... entry ID 4 ... Processed data points 500 ...

Pour créer une série temporelle qui affiche le nombre de tous les points de données traités, utilisez un MQL comme celui-ci:

fetch global
| metric 'logging.googleapis.com/user/METRIC_NAME'
| group_by [], sum(sum_from(value))

Pour créer une métrique de distribution basée sur les journaux, consultez la page Configurer les métriques de distribution.

Exclure des colonnes d'un groupe

Vous pouvez utiliser le modificateur drop dans un mappage pour exclure des colonnes d'un groupe. Par exemple, la métrique Kubernetes core_usage_time comporte six colonnes:

fetch k8s_container :: kubernetes.io/container/cpu/core_usage_time
| group_by [project_id, location, cluster_name, namespace_name, container_name]

Si vous n'avez pas besoin de regrouper pod_name, vous pouvez l'exclure avec drop:

fetch k8s_container :: kubernetes.io/container/cpu/core_usage_time
| group_by drop [pod_name]

Sélectionner une série temporelle

Les exemples de cette section montrent comment sélectionner des séries temporelles spécifiques dans une table d'entrée.

Sélectionner la série temporelle la plus élevée ou la plus basse

Pour afficher les données de séries temporelles des trois instances Compute Engine présentant le niveau le plus élevé d'utilisation du processeur dans votre projet, saisissez la requête suivante :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| top 3

La capture d'écran suivante montre le résultat pour un projet :

Le graphique montre les trois séries temporelles présentant le niveau le plus élevé d'utilisation.

Vous pouvez récupérer les séries temporelles présentant le niveau le plus faible d'utilisation du processeur en remplaçant top par bottom.

L'opération top génère une table avec un nombre spécifié de séries temporelles sélectionnées dans sa table d'entrée. Les séries temporelles incluses dans la sortie a la plus grande valeur pour un aspect des séries temporelles.

Étant donné que cette requête ne spécifie pas d'ordre d'ordre des séries temporelles, elle renvoie les séries temporelles ayant la valeur la plus élevée pour le point le plus récent. Pour spécifier comment déterminer les séries temporelles qui ont la valeur la plus élevée, vous pouvez fournir un argument à l'opération top. Par exemple, la requête précédente est équivalente à la requête suivante:

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| top 3, val()

L'expression val() sélectionne la valeur du point le plus récent dans chaque série temporelle à laquelle elle est appliquée. Par conséquent, la requête renvoie les séries temporelles ayant la plus grande valeur pour le point le plus récent.

Vous pouvez fournir une expression qui effectue une agrégation sur tout ou partie des points d'une série temporelle pour indiquer la valeur de tri. La valeur suivante prend la moyenne de tous les points des 10 dernières minutes :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| top 3, mean(val()).within(10m)

Si la fonction within n'est pas utilisée, la fonction mean est appliquée aux valeurs de tous les points affichés dans les séries temporelles.

L'opération bottom fonctionne d'une manière semblable. La requête suivante recherche la valeur du plus grand point de chaque série temporelle avec max(val()), puis sélectionne les trois séries temporelles pour lesquelles cette valeur est la plus faible :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| bottom 3, max(val())

La capture d'écran suivante montre un graphique affichant les flux avec les plus petits pics:

Le graphique montre les trois séries temporelles présentant le niveau le plus élevé d'utilisation.

Exclure les n résultats supérieurs ou inférieurs de la série temporelle

Imaginons que vous disposiez de nombreuses instances de VM Compute Engine. Quelques-unes de ces instances consomment beaucoup plus de mémoire que la plupart des instances. En raison de ces anomalies, il est plus difficile de détecter les modèles d'utilisation d'un groupe plus important. Les graphiques d'utilisation du processeur se présentent comme suit:

Le graphique montre de nombreuses lignes d'utilisation du processeur, avec plusieurs anomalies.

Vous souhaitez exclure les trois valeurs aberrantes du graphique afin de voir plus clairement les tendances du groupe global.

Pour exclure les trois premières séries temporelles dans une requête qui récupère les séries temporelles pour l'utilisation du processeur Compute Engine, utilisez l'opération de table top pour identifier la série temporelle et l'opération de table outer_join pour exclure la série temporelle des résultats. Vous pouvez utiliser la requête suivante:

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| {
    top 3 | value [is_default_value: false()]
  ;
    ident
  }
| outer_join true(), _
| filter is_default_value
| value drop [is_default_value]

L'opération fetch affiche une table de séries temporelles sur l'utilisation du processeur de toutes les instances. Cette table est ensuite traitée en deux tables:

  • L'opération de table top n génère une table qui contient la série temporelle n avec les valeurs les plus élevées. Dans ce cas, n = 3. La table obtenue contient les trois séries temporelles à exclure.

    La table contenant les trois premières séries temporelles est ensuite redirigée vers une opération de table value. Cette opération ajoute une autre colonne à chacune des séries temporelles des trois premières tables. La valeur booléenne false est donnée à cette colonne, is_default_value, pour toutes les séries temporelles de la table des trois premières.

  • L'opération ident renvoie la même table que celle qui y a été redirigée : la table d'origine des séries temporelles d'utilisation du processeur. Aucune des séries temporelles de ce tableau ne comporte la colonne is_default_value.

Les trois tables du haut et la table d'origine sont ensuite redirigées vers l'opération de table outer_join. Les trois premières sont la table de gauche dans la jointure et la table récupérée est la table de droite dans la jointure. La jointure externe est configurée pour fournir la valeur true comme valeur de tout champ qui n'existe pas dans une ligne jointe. Le résultat de la jointure externe est une table fusionnée. Les lignes des trois premières conservent la colonne is_default_value avec la valeur false, et toutes les lignes de la table d'origine qui ne figuraient pas également dans les trois premières tables obtenant la colonne is_default_value avec la valeur true.

La table résultant de la jointure est ensuite transmise à l'opération de table filter, qui filtre les lignes dont la valeur est false dans la colonne is_default_value. La table obtenue contient les lignes de la table récupérée à l'origine, sans celles des trois premières tables. Cette table contient l'ensemble de séries temporelles prévu, plus is_default_column.

La dernière étape consiste à supprimer la colonne is_default_column ajoutée par la jointure, afin que la table de sortie contienne les mêmes colonnes que la table initialement récupérée.

La capture d'écran suivante montre le graphique de la requête précédente:

Le graphique montre de nombreuses lignes d'utilisation du processeur, sans les anomalies.

Vous pouvez créer une requête pour exclure la série temporelle présentant l'utilisation du processeur la plus faible en remplaçant top n par bottom n.

La possibilité d'exclure des valeurs aberrantes peut s'avérer utile si vous souhaitez définir une alerte, mais que vous ne voulez pas qu'elles la déclenchent en permanence. La requête d'alerte suivante utilise la même logique d'exclusion que la requête précédente pour surveiller l'utilisation de la limite de processeur par un ensemble de pods Kubernetes après avoir exclu les deux pods principaux:

fetch k8s_container
| metric 'kubernetes.io/container/cpu/limit_utilization'
| filter (resource.cluster_name == 'CLUSTER_NAME' &&
          resource.namespace_name == 'NAMESPACE_NAME' &&
          resource.pod_name =~ 'POD_NAME')
| group_by 1m, [value_limit_utilization_max: max(value.limit_utilization)]
| {
    top 2 | value [is_default_value: false()]
  ;
    ident
  }
| outer_join true(), _
| filter is_default_value
| value drop [is_default_value]
| every 1m
| condition val(0) > 0.73 '1'

Sélectionner le haut ou le bas dans les groupes

Les opérations de table top et bottom sélectionnent des séries temporelles dans l'ensemble de la table d'entrée. Les opérations top_by et bottom_by regroupent les séries temporelles d'une table, puis choisissent un certain nombre de séries temporelles dans chaque groupe.

La requête suivante sélectionne dans chaque zone la série temporelle ayant la plus haute valeur maximale :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| top_by [zone], 1, max(val())

Le graphique montre la valeur maximale la plus haute par zone.

L'expression [zone] indique qu'un groupe est constitué de la série temporelle ayant la même valeur que la colonne zone. La valeur 1 dans top_by indique le nombre de séries temporelles à sélectionner dans le groupe de chaque zone. L'expression max(val()) recherche la plus grande valeur dans la période du graphique pour chaque série temporelle.

Vous pouvez utiliser n'importe quelle fonction d'agrégation à la place de max. Dans l'exemple suivant, l'agrégateur mean et within sont utilisés pour spécifier la plage de tri de 20 minutes. Les deux premières séries temporelles de chaque zone sont sélectionnées :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| top_by [zone], 2, mean(val()).within(20m)

Le graphique montre les deux pics moyens les plus élevés dans une plage de 20 minutes.

Dans l'exemple précédent, il n'y a qu'une seule instance dans la zone us-central-c. Il n'y a donc qu'une seule série temporelle renvoyée. Il n'y a pas de "top 2" dans le groupe.

Combiner les sélections avec union

Vous pouvez combiner des opérations de sélection telles que top et bottom pour créer des graphiques qui affichent les deux. Par exemple, la requête suivante renvoie la série temporelle unique présentant la valeur maximale et la série temporelle unique présentant la valeur minimale :

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| {
    top 1, max(val())
  ;
    bottom 1, min(val())
  }
| union

Le graphique obtenu affiche deux lignes, l'une contenant la valeur la plus élevée et l'autre contenant la plus basse :

Le graphique montre les séries temporelles présentant les valeurs les plus élevées et les plus faibles.

Vous pouvez utiliser des accolades ({ }) pour spécifier des séquences d'opérations, chacune produisant une table de séries temporelles en sortie. Les opérations individuelles sont séparées à l'aide d'un point-virgule (;).

Dans cet exemple, l'opération fetch renvoie une seule table, qui est canalisée vers chacune des deux opérations de la séquence, une opération top et une opération bottom. Chacune de ces opérations génère une table de sortie basée sur la même table d'entrée. L'opération union combine ensuite les deux tables en une seule, qui s'affiche sur le graphique.

Pour en savoir plus sur les opérations de séquencement à l'aide de { }, consultez la documentation de référence sur Structure de la requête.

Combiner des séries temporelles avec différentes valeurs pour un même libellé

Supposons que vous ayez plusieurs séries temporelles pour le même type de métrique et que vous souhaitiez en combiner plusieurs. Si vous souhaitez les sélectionner en fonction des valeurs d'un seul libellé, vous ne pouvez pas créer la requête à l'aide de l'interface du générateur de requêtes dans l'explorateur de métriques. Vous devez filtrer sur au moins deux valeurs différentes du même libellé, mais l'interface du générateur de requêtes nécessite qu'une série temporelle corresponde à tous les filtres à sélectionner : la mise en correspondance des libellés est un test AND. Aucune série temporelle ne peut avoir deux valeurs différentes pour le même libellé, mais vous ne pouvez pas créer de test OR pour les filtres dans le générateur de requêtes.

La requête suivante récupère la série temporelle de la métrique instance/disk/max_read_ops_count Compute Engine pour deux instances Compute Engine spécifiques et aligne le résultat sur des intervalles d'une minute:

fetch gce_instance
| metric 'compute.googleapis.com/instance/disk/max_read_ops_count'
| filter (resource.instance_id == '1854776029354445619' ||
          resource.instance_id == '3124475757702255230')
| every 1m

Le graphique suivant montre le résultat de cette requête:

Le graphique montre deux séries temporelles sélectionnées par valeur du même libellé.

Si vous souhaitez obtenir la somme des valeurs max_read_ops_count maximales de ces deux VM et les additionner, vous pouvez procéder comme suit:

  • Pour trouver la valeur maximale de chaque série temporelle, utilisez l'opérateur de table group_by, en spécifiant la même période d'alignement d'une minute et en agrégeant la période avec l'agrégateur max pour créer une colonne nommée max_val_of_read_ops_count_max dans la table de sortie.
  • Pour trouver la somme des séries temporelles, utilisez l'opérateur de table group_by et l'agrégateur sum dans la colonne max_val_of_read_ops_count_max.

Voici la requête:

fetch gce_instance
| metric 'compute.googleapis.com/instance/disk/max_read_ops_count'
| filter (resource.instance_id == '1854776029354445619' ||
          resource.instance_id == '3124475757702255230')
| group_by 1m, [max_val_of_read_ops_count_max: max(value.max_read_ops_count)]
| every 1m
| group_by [], [summed_value: sum(max_val_of_read_ops_count_max)]

Le graphique suivant montre le résultat de cette requête:

Le graphique montre la somme de deux séries temporelles sélectionnées par valeur du même libellé.

Calculer les statistiques de centiles dans le temps et pour l'ensemble des flux

Pour calculer une valeur de flux de centile sur une fenêtre glissante séparément pour chaque flux, utilisez une opération group_by temporelle. Par exemple, la requête suivante calcule la valeur du 99e centile d'un flux sur une fenêtre glissante d'une heure:

fetch gce_instance :: compute.googleapis.com/instance/cpu/utilization
| group_by 1h, percentile(val(), 99)
| every 1m

Pour calculer la même statistique de centile à un moment précis sur plusieurs flux, plutôt qu'au sein d'un même flux, utilisez une opération spatiale group_by:

fetch gce_instance :: compute.googleapis.com/instance/cpu/utilization
| group_by [], percentile(val(), 99)

Ratios de calcul

Supposons que vous ayez créé un service Web distribué qui s'exécute sur des instances de VM Compute Engine et utilise Cloud Load Balancing.

Vous souhaitez afficher un graphique indiquant le ratio entre les requêtes qui renvoient des réponses HTTP 500 (erreurs internes) et le nombre total de requêtes, c'est-à-dire le ratio requêtes/échecs. Cette section illustre plusieurs façons de calculer ce ratio.

Cloud Load Balancing utilise le type de ressource surveillée http_lb_rule. Le type de ressource surveillée http_lb_rule possède un libellé matched_url_path_rule qui enregistre le préfixe des URL définies dans la règle. La valeur par défaut est UNMATCHED.

Le type de métrique loadbalancing.googleapis.com/https/request_count comporte un libellé response_code_class. Ce libellé capture la classe des codes de réponse.

Utiliser outer_join et div

La requête suivante détermine les réponses 500 pour chaque valeur du libellé matched_url_path_rule dans chaque ressource surveillée http_lb_rule de votre projet. Elle joint ensuite cette table de comptage des échecs à la table d'origine, qui contient tous les décomptes de réponses et divise les valeurs pour afficher le ratio entre les réponses d'échec et le nombre total de réponses :

fetch https_lb_rule::loadbalancing.googleapis.com/https/request_count
| {
    filter response_code_class = 500
  ;
    ident
  }
| group_by [matched_url_path_rule]
| outer_join 0
| div

Le graphique suivant montre le résultat pour un projet :

Le graphique montre le ratio entre les réponses d'échec et le nombre total de réponses obtenu par jointure.

Les parties ombrées autour des lignes du graphique sont des bandes minimales/maximales. Pour en savoir plus, consultez la section Bandes minimales/maximales.

L'opération fetch génère une table de séries temporelles contenant les décomptes de requêtes pour toutes les requêtes à équilibrage de charge. Cette table est traitée de deux manières par les deux séquences d'opérations entre accolades :

  • filter response_code_class = 500 ne renvoie que les séries temporelles associées au libellé response_code_class avec la valeur 500. La série temporelle obtenue comptabilise les requêtes avec des codes de réponse HTTP 5xx (erreur).

    Cette table est le numérateur du ratio.

  • L'opération ident, ou identité, génère son entrée. Elle renvoie donc la table récupérée à l'origine. Il s'agit de la table qui contient les séries temporelles avec le nombre de chaque code de réponse.

    Cette table est le dénominateur du ratio.

Les tables de numérateur et de dénominateur, générées respectivement par les opérations filter et ident, sont traitées séparément par l'opération group_by. L'opération group_by regroupe les séries temporelles de chaque table en fonction de la valeur du libellé matched_url_path_rule et additionne les décomptes pour chaque valeur du libellé. Cette opération group_by n'indique pas explicitement la fonction d'agrégateur. Une valeur par défaut, sum, est utilisée.

  • Pour la table filtrée, le résultat group_by correspond au nombre de requêtes renvoyant une réponse 500 pour chaque valeur matched_url_path_rule.

  • Pour la table des identités, le résultat group_by correspond au nombre total de requêtes pour chaque valeur matched_url_path_rule.

Ces tables sont canalisées vers l'opération outer_join, qui associe les séries temporelles aux valeurs de libellé correspondantes, une dans chacune des deux tables d'entrée. Les séries temporelles associées sont compressées en faisant correspondre l'horodatage de chaque point d'une série temporelle à celui d'un point de l'autre série temporelle. Pour chaque paire de points mis en correspondance, outer_join génère un seul point de sortie avec deux valeurs, provenant de chacune des tables d'entrée. La série temporelle compressée est générée par la jointure avec les mêmes libellés que les deux séries temporelles d'entrée.

Avec une jointure externe, si un point de la deuxième table ne possède pas de point de correspondance dans la première, une valeur de remplacement doit être fournie. Dans cet exemple, un point avec la valeur 0 (argument de l'opération outer_join) est utilisé.

Enfin, l'opération div prend chaque point avec deux valeurs et divise les valeurs pour générer un seul point de sortie : il s'agit du ratio entre les réponses 500 et toutes les réponses pour chaque mappage d'URL.

La chaîne div ici est en fait le nom de la fonction div, qui divise deux valeurs numériques. Cependant, elle est utilisée ici comme opération. Lorsqu'elles sont utilisées en tant qu'opérations, les fonctions telles que div attendent deux valeurs dans chaque point d'entrée (ce que garantit join) et génèrent une seule valeur pour le point de sortie correspondant.

La partie | div de la requête est un raccourci pour | value val(0) / val(1). L'opération value permet à des expressions arbitraires sur les colonnes de valeur d'une table d'entrée de générer les colonnes de valeur de la table de sortie. Pour plus d'informations, consultez les pages de référence sur l'opération value et les expressions.

Utiliser "ratio"

La fonction div peut être remplacée par n'importe quelle fonction sur deux valeurs. Toutefois, comme les ratios sont fréquemment utilisés, la langage MQL fournit une opération de table ratio qui les calcule directement.

La requête ci-dessous équivaut à la version précédente, utilisant outer_join et div :

fetch https_lb_rule::loadbalancing.googleapis.com/https/request_count
| {
    filter response_code_class = 500
  ;
    ident
  }
| group_by [matched_url_path_rule]
| ratio

Dans cette version, l'opération ratio remplace les opérations outer_join 0 | div de la version précédente et génère le même résultat.

Notez que ratio n'utilise outer_join pour fournir un 0 au numérateur que si les entrées du numérateur et du dénominateur ont les mêmes étiquettes pour identifier chaque série temporelle, ce qui est requis par MQL outer_join. Si l'entrée du numérateur comporte des étiquettes supplémentaires, il n'y aura de sortie pour aucun point manquant dans le dénominateur.

Utiliser group_by et /

Il existe une autre façon de calculer le ratio entre les réponses d'erreur et le nombre total de réponses. Dans ce cas, comme le numérateur et le dénominateur du ratio sont dérivés de la même série temporelle, vous pouvez également calculer le ratio en effectuant uniquement un regroupement. La requête suivante illustre cette approche :

fetch https_lb_rule::loadbalancing.googleapis.com/https/request_count
| group_by [matched_url_path_rule],
    sum(if(response_code_class = 500, val(), 0)) / sum(val())

Cette requête utilise une expression d'agrégation basée sur le ratio de deux sommes :

  • La première somme (sum) utilise la fonction if pour comptabiliser les libellés ayant la valeur 500 et 0 pour les autres. La fonction sum calcule le nombre de requêtes ayant renvoyé 500.

  • La seconde somme (sum) additionne les décomptes de toutes les requêtes, val().

Les deux sommes sont ensuite divisées, ce qui donne le ratio entre le nombre de réponses 500 et le nombre total de réponses. Cette requête génère le même résultat que les requêtes figurant dans les sections Utiliser outer_join et div et Utiliser ratio.

Utiliser "filter_ratio_by"

Comme les ratios sont souvent calculés en divisant deux sommes dérivées de la même table, le langage MQL fournit l'opération filter_ratio_by à cet effet. La requête suivante effectue la même opération que la version précédente, qui divise explicitement les sommes :

fetch https_lb_rule::loadbalancing.googleapis.com/https/request_count
| filter_ratio_by [matched_url_path_rule], response_code_class = 500

Le premier opérande de l'opération filter_ratio_by, ici [matched_url_path_rule], indique comment regrouper les réponses. La seconde opération, ici response_code_class = 500, agit comme une expression de filtrage pour le numérateur.

  • La table de dénominateur est le résultat du regroupement de la table extraite par matched_url_path_rule et agrégée à l'aide de sum.
  • La table de numérateur est la table extraite, filtrée pour les séries temporelles ayant le code de réponse HTTP 5xx, puis regroupée par matched_url_path_rule et agrégée à l'aide de sum.

Ratios et métriques de quotas

Pour configurer des requêtes et des alertes sur les métriques de quota serviceruntime et les métriques de quota spécifiques aux ressources afin de surveiller la consommation de votre quota, vous pouvez utiliser MQL. Pour en savoir plus et obtenir des exemples, consultez la page Utiliser des métriques de quota.

Calcul arithmétique

Parfois, vous souhaiterez peut-être effectuer une opération arithmétique sur des données avant de les représenter dans un graphique. Par exemple, vous pouvez effectuer un scaling de séries temporelles, convertir les données en échelle logarithmique ou représenter graphiquement la somme de deux séries temporelles. Pour obtenir la liste des fonctions arithmétiques disponibles dans MQL, consultez la section Arithmétique.

Pour effectuer le scaling d'une série temporelle, utilisez la fonction mul. Par exemple, la requête suivante récupère la série temporelle, puis multiplie chaque valeur par 10:

  fetch gce_instance
  | metric 'compute.googleapis.com/instance/disk/read_bytes_count'
  | mul(10)

Pour additionner deux séries temporelles, configurez votre requête de façon à extraire deux tables de séries temporelles, joignez ces résultats, puis appelez la fonction add. L'exemple suivant illustre une requête qui calcule la somme du nombre d'octets lus et écrits dans les instances Compute Engine:

  fetch gce_instance
  | { metric 'compute.googleapis.com/instance/disk/read_bytes_count'
    ; metric 'compute.googleapis.com/instance/disk/write_bytes_count' }
  | outer_join 0
  | add

Pour soustraire le nombre d'octets écrits du nombre d'octets lus, remplacez add par sub dans l'expression précédente.

MQL utilise les étiquettes des ensembles de tables renvoyés par les première et deuxième extraction pour déterminer comment joindre les tables:

  • Si la première table contient une étiquette introuvable dans la deuxième, MQL ne peut pas effectuer d'opération outer_join sur les tables et renvoie donc une erreur. Par exemple, la requête suivante provoque une erreur, car le libellé metric.throttle_reason est présent dans la première table, mais pas dans la deuxième:

     fetch gce_instance
      | { metric 'compute.googleapis.com/instance/disk/throttled_read_bytes_count'
        ; metric 'compute.googleapis.com/instance/disk/write_bytes_count' }
      | outer_join 0
      | add
    

    Une façon de résoudre ce type d'erreur consiste à appliquer des clauses de regroupement pour vous assurer que les deux tables ont les mêmes étiquettes. Par exemple, vous pouvez regrouper les libellés de toutes les séries temporelles:

     fetch gce_instance
      | { metric 'compute.googleapis.com/instance/disk/throttled_read_bytes_count'
          | group_by []
        ; metric 'compute.googleapis.com/instance/disk/write_bytes_count'
          | group_by [] }
      | outer_join 0
      | add
    
  • Si les libellés des deux tables correspondent, ou si la deuxième table contient une étiquette introuvable dans la première table, la jointure externe est autorisée. Par exemple, la requête suivante ne provoque pas d'erreur même si le libellé metric.throttle_reason est présent dans la deuxième table, mais pas dans la première:

     fetch gce_instance
      | { metric 'compute.googleapis.com/instance/disk/write_bytes_count'
        ; metric 'compute.googleapis.com/instance/disk/throttled_read_bytes_count' }
      | outer_join 0
      | sub
    

    Une série temporelle présente dans la première table peut avoir des valeurs d'étiquettes correspondant à plusieurs séries temporelles de la deuxième table. MQL effectue donc l'opération de soustraction pour chaque paire.

Décalage temporel

Parfois, vous souhaitez comparer ce qui se passe actuellement et ce qui est survenu dans le passé. Pour vous permettre de comparer des données antérieures aux données actuelles, MQL fournit une opération de table time_shift pour déplacer les données du passé vers la période actuelle.

Ratios au fil du temps

La requête suivante utilise time_shift, join et div pour calculer le ratio de l'utilisation moyenne dans chaque entre la période actuelle et une semaine auparavant.

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| group_by [zone], mean(val())
| {
    ident
  ;
    time_shift 1w
  }
| join | div

Le graphique suivant montre un résultat possible de cette requête :

Le graphique montre le ratio des données actuelles et décalées dans le temps.

Les deux premières opérations extraient la série temporelle, puis les regroupent par zone en calculant les valeurs moyennes de chacune. La table obtenue est ensuite transmise à deux opérations. La première opération, ident, transmet la table sans la modifier.

La seconde opération, time_shift, ajoute la période (1 semaine) aux horodatages des valeurs dans la table, ce qui décale les données d'une semaine en avant. Cette modification permet d'aligner les horodatages des données plus anciennes de la deuxième table avec les horodatages des données actuelles de la première table.

La table non modifiée et la table décalée dans le temps sont ensuite combinées à l'aide d'une opération join interne. L'opération join génère une table de séries temporelles où chaque point a deux valeurs : l'utilisation actuelle et l'utilisation une semaine auparavant. La requête utilise ensuite l'opération div pour calculer le ratio entre la valeur actuelle et la valeur de la semaine passée.

Données passées et présentes

En combinant time_shift avec union, vous pouvez créer un graphique qui affiche simultanément les données passées et présentes. Par exemple, la requête suivante renvoie l'utilisation moyenne globale pour la période actuelle et pour la semaine précédente. À l'aide de union, vous pouvez afficher ces deux résultats sur le même graphique.

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| group_by []
| {
     add [when: "now"]
  ;
     add [when: "then"] | time_shift 1w
  }
| union

Le graphique suivant montre un résultat possible de cette requête :

Le graphique indique l'utilisation moyenne actuelle et passée.

Cette requête extrait la série temporelle, puis utilise group_by [] pour les combiner en une seule série temporelle sans libellé, ce qui laisse les points de données d'utilisation du processeur. Ce résultat est transmis à deux opérations. La première ajoute une colonne pour un nouveau libellé appelé when avec la valeur now. La seconde ajoute un libellé appelé when avec la valeur then et transmet le résultat à l'opération time_shift pour décaler les valeurs d'une semaine. Cette requête utilise le modificateur de mappage add. Pour en savoir plus, consultez la section Mappages.

Les deux tables, chacune contenant des données pour une seule série temporelle, sont transmises à union, qui génère une table contenant les séries temporelles des deux tables d'entrée.

Étapes suivantes

Pour obtenir une présentation des structures du langage MQL, consultez la page À propos du langage MQL.

Pour obtenir une description complète du langage MQL, consultez la documentation de référence sur le langage MQL.

Pour en savoir plus sur l'interaction avec les graphiques, consultez Utiliser des graphiques.