Exemples de requêtes SQL

Ce document contient des exemples de requêtes que vous pouvez utiliser pour interroger vos données de journaux et de trace.

Prise en charge du langage SQL

Les requêtes utilisées sur la page Analyse de journaux sont compatibles avec les fonctions GoogleSQL, à quelques exceptions près.

Les commandes SQL suivantes ne sont pas compatibles avec les requêtes SQL émises à l'aide de la page Analyse de journaux :

  • Commandes LDD et LMD
  • Fonctions JavaScript définies par l'utilisateur
  • Fonctions BigQuery ML
  • Variables SQL

Les éléments suivants ne sont compatibles que lorsque vous interrogez un ensemble de données associé à l'aide des pages BigQuery Studio et Looker Studio, ou à l'aide de l'outil de ligne de commande bq :

  • Fonctions JavaScript définies par l'utilisateur
  • Fonctions BigQuery ML
  • Variables SQL

Bonnes pratiques

Pour définir la période de votre requête, nous vous recommandons d'utiliser le sélecteur de période. Par exemple, pour afficher les données de la semaine dernière, sélectionnez Les 7 derniers jours dans le sélecteur de période. Vous pouvez également utiliser le sélecteur de période pour spécifier une heure de début et de fin, une heure à afficher et un fuseau horaire.

Données des journaux

Si vous incluez un champ timestamp dans la clause WHERE, le paramètre du sélecteur de période n'est pas utilisé. L'exemple suivant montre comment filtrer par code temporel :

-- Matches log entries whose timestamp is within the most recent 1 hour.
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

Données de trace

Si vous incluez un champ start_time dans la clause WHERE, le paramètre du sélecteur de période n'est pas utilisé. L'exemple suivant montre comment filtrer par code temporel :

-- Matches trace spans whose start_time is within the most recent 1 hour.
WHERE start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

Pour savoir comment filtrer par heure, consultez Fonctions temporelles et Fonctions d'horodatage.

Avant de commencer

  1. Connectez-vous à votre compte Google Cloud . Si vous débutez sur Google Cloud, créez un compte pour évaluer les performances de nos produits en conditions réelles. Les nouveaux clients bénéficient également de 300 $de crédits sans frais pour exécuter, tester et déployer des charges de travail.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Activez l'API Observability.

    Rôles requis pour activer les API

    Pour activer les API, vous avez besoin du rôle IAM Administrateur Service Usage (roles/serviceusage.serviceUsageAdmin), qui contient l'autorisation serviceusage.services.enable. Découvrez comment attribuer des rôles.

    Activer l'API

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Activez l'API Observability.

    Rôles requis pour activer les API

    Pour activer les API, vous avez besoin du rôle IAM Administrateur Service Usage (roles/serviceusage.serviceUsageAdmin), qui contient l'autorisation serviceusage.services.enable. Découvrez comment attribuer des rôles.

    Activer l'API

  8. Pour obtenir les autorisations nécessaires pour charger la page Log Analytics, écrire, exécuter et enregistrer des requêtes privées sur vos données de trace, demandez à votre administrateur de vous accorder les rôles IAM suivants :

    • Accesseur de vue d'observabilité (roles/observability.viewAccessor) sur les vues d'observabilité que vous souhaitez interroger. Ce rôle est compatible avec les conditions IAM, qui vous permettent de limiter l'accès à une vue spécifique. Si vous n'associez pas de condition à l'attribution de rôle, le compte principal peut accéder à toutes les vues d'observabilité. Les vues d'observabilité sont disponibles en version Preview publique.
    • Utilisateur Observability Analytics (roles/observability.analyticsUser) sur votre projet Ce rôle contient les autorisations requises pour enregistrer et exécuter des requêtes privées, et pour exécuter des requêtes partagées.
    • Lecteur de journaux (roles/logging.viewer) sur votre projet.
    • Accesseur de vues de journaux (roles/logging.viewAccessor) sur le projet qui stocke les vues de journaux que vous souhaitez interroger.

    Pour en savoir plus sur l'attribution de rôles, consultez Gérer l'accès aux projets, aux dossiers et aux organisations.

    Vous pouvez également obtenir les autorisations requises avec des rôles personnalisés ou d'autres rôles prédéfinis.

Utiliser les requêtes sur cette page

  1. Dans la console Google Cloud , accédez à la page Analyse de journaux :

    Accéder à l'Analyse de journaux

    Si vous utilisez la barre de recherche pour trouver cette page, sélectionnez le résultat dont le sous-titre est Logging.

  2. Dans le volet Requête, cliquez sur  SQL, puis copiez et collez une requête dans le volet de requête SQL.

    Données des journaux

    Avant de copier une requête, dans la clause FROM, remplacez les champs suivants :

    • PROJECT_ID : identifiant du projet.
    • LOCATION : emplacement de la vue des journaux ou de la vue des données analytiques.
    • BUCKET_ID : nom ou ID du bucket de journaux.
    • LOG_VIEW_ID : identifiant de la vue de journal, limité à 100 caractères et ne pouvant inclure que des lettres, des chiffres, des traits de soulignement et des traits d'union.

    Voici le format de la clause FROM pour une vue Journaux :

    FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
    

    Les exemples de journaux sur cette page interrogent une vue de journaux. Pour interroger une vue Analytics, utilisez le format de chemin d'accès suivant : `analytics_view.PROJECT_ID.LOCATION.ANALYTICS_VIEW_ID`. Dans l'expression précédente, PROJECT_ID correspond à l'ID de votre projet, et LOCATION et ANALYTICS_VIEW_ID correspondent à l'emplacement et au nom de votre vue Analytics.

    Données de trace

    Voici le format de la cause FROM pour interroger la vue _AllSpans :

    FROM `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
    

    La clause FROM contient les champs suivants :

    • PROJECT_ID : identifiant du projet.
    • LOCATION : emplacement du bucket d'observabilité.
    • _Trace est le nom du bucket d'observabilité.
    • Spans est le nom de l'ensemble de données.
    • _AllSpans est le nom de la vue.

Pour utiliser les requêtes présentées dans ce document sur la page BigQuery Studio ou l'outil de ligne de commande bq, modifiez la clause FROM et saisissez le chemin d'accès à l'ensemble de données associé.

Données des journaux

Par exemple, pour interroger la vue _AllLogs sur l'ensemble de données associé nommé mydataset qui se trouve dans le projet myproject, le chemin d'accès est myproject.mydataset._AllLogs.

Données de trace

Par exemple, pour interroger la vue _AllSpans sur l'ensemble de données associé nommé my_linked_dataset qui se trouve dans le projet myproject, le chemin d'accès est `myproject.my_linked_dataset._AllSpans`.

Cas d'utilisation courants

Cette section liste plusieurs cas d'utilisation courants qui peuvent vous aider à créer vos requêtes personnalisées.

Afficher les entrées de journal dans le bucket de journaux par défaut

Pour interroger le bucket _Default, exécutez la requête suivante :

SELECT
  timestamp, severity, resource.type, log_name, text_payload, proto_payload, json_payload
FROM
  `PROJECT_ID.LOCATION._Default._AllLogs`
-- Limit to 1000 entries
LIMIT 1000

Extraire la valeur d'un champ par expression régulière

Pour extraire une valeur d'une chaîne à l'aide d'une expression régulière, utilisez la fonction REGEXP_EXTRACT :

SELECT
  -- Display the timestamp, and the part of the name that begins with test.
  timestamp, REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Get the value of jobName, which is a subfield in a JSON structure.
  JSON_VALUE(json_payload.jobName) IS NOT NULL
ORDER BY timestamp DESC
LIMIT 20

Pour en savoir plus, consultez la documentation REGEXP_EXTRACT.

Pour les correspondances de sous-chaînes, comme dans la requête précédente, l'utilisation de la fonction CONTAINS_SUBSTR permet d'obtenir une requête plus efficace.

Afficher toutes les données de trace

Pour interroger la vue _AllSpans, exécutez la requête suivante :

-- Display all data.
SELECT *
FROM `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
-- Limit to 10 entries.
LIMIT 10

Afficher les informations sur les étendues communes

Pour afficher des informations communes sur les spans, comme l'heure de début et la durée, exécutez la requête suivante :

SELECT
  start_time,
  -- Set the value of service name based on the first non-null value in the list.
  COALESCE(
    JSON_VALUE(resource.attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."g.co/gae/app/module"')) AS service_name,
  name AS span_name,
  duration_nano,
  status.code AS status,
  trace_id,
  span_id
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
LIMIT 10

Pour en savoir plus, consultez Expressions conditionnelles.

Afficher les 50e et 99e centiles de la latence de la portée

Pour afficher les 50e et 99e centiles de la latence pour chaque service RPC, exécutez la requête suivante :

SELECT
  -- Compute 50th and 99th percentiles for each service
  STRING(attributes['rpc.service']) || '/' || STRING(attributes['rpc.method']) AS rpc_service_method,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(50)] AS duration_nano_p50,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(99)] AS duration_nano_p99
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE
  -- Matches spans whose kind field has a value of 2 (SPAN_KIND_SERVER).
  kind = 2
GROUP BY rpc_service_method

Pour en savoir plus sur l'énumération, consultez la documentation OpenTelemetry : SpanKind.

Pour afficher les résultats sous forme graphique, vous pouvez créer un graphique dont la dimension est définie sur rpc_service_method. Vous pouvez ajouter deux mesures : l'une pour la moyenne de la valeur duration_nano_p50 et l'autre pour la moyenne du champ duration_nano_p99.

Filtrer les entrées de journal

Pour appliquer un filtre à votre requête, ajoutez une clause WHERE. La syntaxe que vous utilisez dans cette clause dépend du type de données du champ. Cette section fournit plusieurs exemples pour différents types de données.

Filtrer les entrées de journal par type de charge utile

Les entrées de journal peuvent avoir l'un des trois types de charge utile suivants. Pour filtrer les entrées de journal par type de charge utile, utilisez l'une des clauses suivantes :

  • Charges utiles texte

    -- Matches log entries that have a text payload.
    WHERE text_payload IS NOT NULL
    
  • Charges utiles JSON

    -- Matches log entries that have a JSON payload.
    WHERE json_payload IS NOT NULL
    
  • Charges utiles proto

    -- Matches log entries that have a proto payload.
    -- Because proto_payload has a data type of RECORD, this statement tests
    -- whether a mandatory subfield exits.
    WHERE proto_payload.type IS NOT NULL
    

Dans les résultats de la requête, les champs json_payload et proto_payload sont affichés au format JSON, que vous pouvez parcourir.

Filtrer les données de journaux par code temporel

Pour filtrer les entrées de journal par code temporel, nous vous recommandons d'utiliser le sélecteur de plage de dates. Toutefois, vous pouvez également spécifier le timestamp dans la clause WHERE :

-- Matches log entries whose timestamp is within the most recent hour
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

Pour savoir comment filtrer par heure, consultez Fonctions temporelles et Fonctions d'horodatage.

Filtrer par ressource

Pour filtrer vos données de journaux et de traces par ressource, ajoutez une instruction resource.type à la clause WHERE :

-- Matches log entries whose resource type is gce_instance
WHERE resource.type = "gce_instance"

Filtrer par gravité

Pour filtrer vos données de journaux par niveau de gravité, ajoutez une instruction severity à la clause WHERE :

-- Matches log entries whose severity is INFO or ERROR
WHERE severity IS NOT NULL AND severity IN ('INFO', 'ERROR')

Vous pouvez également filtrer vos entrées de journal par severity_number, qui est un nombre entier. Par exemple, la clause suivante correspond à toutes les entrées de journal dont le niveau de gravité est au moins égal à NOTICE :

-- Matches log entries whose severity level is at least NOTICE
WHERE severity_number IS NOT NULL AND severity_number > 200

Pour en savoir plus sur les valeurs énumérées, consultez LogSeverity.

Filtrer par nom de journal

Pour filtrer vos données de journaux par nom de journal, ajoutez une instruction log_name ou log_id à la clause WHERE :

  • Le nom du journal spécifie le chemin d'accès à la ressource :

    -- Matches log entries that have the following log ID.
    WHERE log_name="projects/cloud-logs-test-project/logs/cloudaudit.googleapis.com%2Factivity"
    
  • L'ID de journal omet le chemin de ressource :

    -- Matches log entries that have the following log id.
    WHERE log_id = "cloudaudit.googleapis.com/data_access"
    

Filtrer les entrées de journal par libellé de ressource

Les libellés de ressources sont stockés sous forme de structure JSON. Pour filtrer selon la valeur d'un champ dans une structure JSON, utilisez la fonction JSON_VALUE :

SELECT
  timestamp, JSON_VALUE(resource.labels.zone) AS zone, json_payload, resource, labels
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Matches log entries whose resource type is gce_instance and whose zone is
  -- us-central1-f. Because resource has data type JSON, you must use JSON_VALUE
  -- to get the value for subfields, like zone.
  resource.type = "gce_instance" AND
  JSON_VALUE(resource.labels.zone) = "us-central1-f"
ORDER BY timestamp ASC

La requête précédente s'appuie sur le format des libellés de ressources tels qu'ils sont stockés dans une entrée de journal. Voici un exemple de champ de ressource :

{
   type: "gce_instance"
   labels: {
      instance_id: "1234512345123451"
      project_id: "my-project"
      zone: "us-central1-f"
   }
}

Pour en savoir plus sur toutes les fonctions permettant de récupérer et de transformer des données JSON, consultez Fonctions JSON.

Filtrer par requête HTTP

Pour n'interroger que les entrées de journal comportant un champ de requête HTTP, utilisez la clause suivante :

-- Matches log entries that have a HTTP request_method field.
-- Don't compare http_request to NULL. This field has a data type of RECORD.
WHERE http_request.request_method IS NOT NULL

Vous pouvez également utiliser l'instruction IN :

-- Matches log entries whose HTTP request_method is GET or POST.
WHERE http_request.request_method IN ('GET', 'POST')

Filtrer par code d'état HTTP

Pour n'interroger que les entrées de journal qui ont un état HTTP, utilisez la clause suivante :

-- Matches log entries that have an http_request.status field.
WHERE http_request.status IS NOT NULL

Filtrer par champ dans un type de données JSON

Pour n'interroger les entrées de journal que lorsque le sous-champ d'un champ avec un type de données JSON a une valeur spécifique, extrayez la valeur à l'aide de la fonction JSON_VALUE :

-- Compare the value of the status field to NULL.
WHERE JSON_VALUE(json_payload.status) IS NOT NULL

La clause précédente est légèrement différente de la suivante :

-- Compare the status field to NULL.
WHERE json_payload.status IS NOT NULL

La première clause teste si la valeur du champ d'état est NULL. La deuxième clause vérifie si le champ d'état existe. Supposons qu'une vue de journal contienne deux entrées de journal. Pour une entrée de journal, le champ json_payload se présente comme suit :

{
    status: {
        measureTime: "1661517845"
    }
}

Pour l'autre entrée de journal, le champ json_payload a une structure différente :

{
    @type: "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished"
    jobName: "projects/my-project/locations/us-central1/jobs/test1"
    relativeUrl: "/food=cake"
    status: "NOT_FOUND"
    targetType: "APP_ENGINE_HTTP"
}

La clause WHERE json_payload.status IS NOT NULL correspond aux deux entrées de journal. Toutefois, la clause WHERE JSON_VALUE(json_payload.status) IS NOT NULL ne correspond qu'à la deuxième entrée de journal.

Filtrer les entrées de trace

Pour appliquer un filtre à votre requête, ajoutez une clause WHERE. La syntaxe que vous utilisez dans cette clause dépend du type de données du champ. Cette section fournit plusieurs exemples pour différents types de données.

Filtrer par types de données de chaîne

Le champ name est stocké en tant que String.

  • Pour n'analyser que les portées où name est spécifié, utilisez la clause suivante :

    -- Matches spans that have a name field.
    WHERE name IS NOT NULL
    
  • Pour n'analyser que les étendues où name a la valeur "POST", utilisez la clause suivante :

    -- Matches spans whose name is POST.
    WHERE STRPOS(name, "POST") > 0
    
  • Pour n'analyser que les portées où name contient la valeur "POST", utilisez l'opérateur LIKE avec des caractères génériques :

    -- Matches spans whose name contains POST.
    WHERE name LIKE "%POST%"
    

Filtrer par types de données entiers

Le champ kind est un nombre entier compris entre zéro et cinq :

  • Pour n'analyser que les portées pour lesquelles kind est spécifié, utilisez la clause suivante :

    -- Matches spans that have field named kind.
    WHERE kind IS NOT NULL
    
  • Pour analyser les portées dont la valeur kind est égale à un ou deux, utilisez la clause suivante :

    -- Matches spans whose kind value is 1 or 2.
    WHERE kind IN (1, 2)
    

Filtrer par types de données RECORD

Certains champs du schéma de trace ont un type de données RECORD. Ces champs peuvent stocker une ou plusieurs structures de données, ou des entrées répétées de la même structure de données.

Filtrer par état ou code d'état

Le champ status est un exemple de champ dont le type de données est RECORD. Ce champ stocke une structure de données, avec des membres libellés code et message.

  • Pour n'analyser les spans que lorsque le champ status.code a une valeur de 1, ajoutez la clause suivante :

    -- Matches spans that have a status.code field that has a value of 1.
    WHERE status.code = 1
    

    Le champ status.code est stocké sous forme d'entier.

  • Pour analyser les étendues où le champ status n'est pas EMPTY, ajoutez la clause suivante :

    -- Matches spans that have status field. When the status field exists, it
    -- must contain a subfield named code.
    -- Don't compare status to NULL, because this field has a data type of RECORD.
    WHERE status.code IS NOT NULL
    

Les champs events et links sont stockés avec un type de données RECORD, mais il s'agit de champs répétés.

  • Pour faire correspondre les étendues comportant au moins un événement, utilisez la clause suivante :

    -- Matches spans that have at least one event. Don't compare events to NULL.
    -- The events field has data type of RECORD and contains a repeated fields.
    WHERE ARRAY_LENGTH(events) > 0
    
  • Pour faire correspondre les portées qui comportent un événement dont le champ name a la valeur message, utilisez la clause suivante :

    WHERE
      -- Exists is true when any event in the array has a name field with the
      -- value of message.
      EXISTS(
        SELECT 1
        FROM UNNEST(events) AS ev
        WHERE ev.name = 'message'
      )
    

Filtrer par types de données JSON

Le champ attributes est de type JSON. Chaque attribut individuel est une paire clé/valeur.

  • Pour n'analyser que les portées où attributes est spécifié, utilisez la clause suivante :

    -- Matches spans where at least one attribute is specified.
    WHERE attributes IS NOT NULL
    
  • Pour n'analyser que les portées dont la clé d'attribut nommée component a une valeur de "proxy", utilisez la clause suivante :

    -- Matches spans that have an attribute named component with a value of proxy.
    WHERE attributes IS NOT NULL
          AND JSON_VALUE(attributes, '$.component') = 'proxy'
    

    Vous pouvez également utiliser une instruction LIKE avec des caractères génériques pour effectuer un test "contient" :

    -- Matches spans that have an attribute named component whose value contains proxy.
    WHERE attributes IS NOT NULL
          AND JSON_VALUE(attributes, '$.component') LIKE '%proxy%'
    

Regrouper et agréger les entrées de journaux

Cette section s'appuie sur les exemples précédents et explique comment regrouper et agréger les entrées de journal. Si vous ne spécifiez pas de regroupement, mais que vous spécifiez une agrégation, un seul résultat est imprimé, car SQL traite toutes les lignes qui satisfont la clause WHERE comme un seul groupe.

Chaque expression SELECT doit être incluse dans les champs de groupe ou être agrégée.

Regrouper les entrées de journaux par code temporel

Pour regrouper les données par code temporel, utilisez la fonction TIMESTAMP_TRUNC, qui tronque un code temporel selon une précision spécifiée, comme HOUR :

SELECT
  -- Truncate the timestamp by hour.
  TIMESTAMP_TRUNC(timestamp, HOUR) AS hour,
  JSON_VALUE(json_payload.status) AS status,
  -- Count the number log entries in each group.
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Matches log entries that have a status field whose value isn't NULL.
  json_payload IS NOT NULL AND JSON_VALUE(json_payload.status) IS NOT NULL
GROUP BY
  -- Group by hour and status
  hour,status
ORDER BY hour ASC

Pour en savoir plus, consultez la documentation TIMESTAMP_TRUNC et les fonctions de date et d'heure.

Regrouper les entrées de journal par ressource

La requête suivante montre comment regrouper les entrées de journal par type de ressource, puis comment compter le nombre d'entrées de journal dans chaque groupe :

SELECT
   -- Count the number of log entries for each resource type
   resource.type, COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
GROUP BY resource.type
LIMIT 100

Regrouper les entrées de journal par gravité

La requête suivante montre comment regrouper les entrées de journal par niveau de gravité, puis comment compter le nombre d'entrées de journal dans chaque groupe :

SELECT
  -- Count the number of log entries for each severity.
  severity, COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  severity IS NOT NULL
GROUP BY severity
ORDER BY severity
LIMIT 100

Regrouper les entrées de journaux par log_id

La requête suivante montre comment regrouper les entrées de journal par ID de journal, puis comment compter le nombre d'entrées de journal dans chaque groupe :

SELECT
  -- Count the number of log entries for each log ID.
  log_id, COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
GROUP BY log_id
ORDER BY count DESC
LIMIT 100

Calculer la latence moyenne des requêtes HTTP par URL

La requête suivante montre comment regrouper les entrées de journal par URL et emplacement de la requête HTTP, puis comment compter le nombre d'entrées de journal dans chaque groupe :

SELECT
  -- Compute the average latency for each group. Because the labels field has a
  -- data type of JSON, use JSON_VALUE to get the value of checker_location.
  JSON_VALUE(labels.checker_location) AS location,
  AVG(http_request.latency.seconds) AS secs, http_request.request_url
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Matches log entries when the request_method field is GET.
  http_request IS NOT NULL AND http_request.request_method IN ('GET')
GROUP BY
  -- Group by request URL and location
  http_request.request_url, location
ORDER BY location
LIMIT 100

Calculer la moyenne des octets envoyés pour un test de sous-réseau

La requête suivante montre comment regrouper les entrées de journal par emplacement spécifié dans les libellés de ressources, puis calculer le nombre d'entrées de journal dans chaque groupe :

SELECT
  -- Compute the average number of bytes sent per location. Because labels has
  -- a data type of JSON, use JSON_VALUE to get the value of the location field.
  -- bytes_sent is a string. Must cast to a FLOAT64 before computing average.
  JSON_VALUE(resource.labels.location) AS location,
  AVG(CAST(JSON_VALUE(json_payload.bytes_sent) AS FLOAT64)) AS bytes
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  resource.type = "gce_subnetwork" AND json_payload IS NOT NULL
GROUP BY
  -- Group by location
  location
LIMIT 100

Pour en savoir plus, consultez les sections Fonctions JSON et Fonctions de conversion.

Compter les entrées de journal avec un champ correspondant à un modèle

Pour renvoyer la sous-chaîne qui correspond à une expression régulière, utilisez la fonction REGEXP_EXTRACT :

SELECT
  -- Extract the value that begins with test.
  -- Count the number of log entries for each name.
  REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  json_payload.jobName IS NOT NULL
GROUP BY name
ORDER BY count
LIMIT 20

Pour obtenir d'autres exemples, consultez la documentation REGEXP_EXTRACT.

Regrouper et agréger les données de trace

Cette section explique comment regrouper et agréger des spans. Si vous ne spécifiez pas de regroupement, mais que vous spécifiez une agrégation, un seul résultat est imprimé, car SQL traite toutes les entrées qui satisfont la clause WHERE comme un seul groupe.

Chaque expression SELECT doit être incluse dans les champs de groupe ou être agrégée.

Regrouper les périodes par heure de début

Pour regrouper les données par heure de début, utilisez la fonction TIMESTAMP_TRUNC, qui tronque un code temporel selon une précision spécifiée, comme HOUR :

SELECT
  -- Truncate the start time to the hour. Count the number of spans per group.
  TIMESTAMP_TRUNC(start_time, HOUR) AS hour,
  status.code AS code,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE
  -- Matches spans shows start time is within the previous 12 hours.
  start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 12 HOUR)
GROUP BY
  -- Group by hour and status code.
  hour, code
ORDER BY hour DESC

Pour en savoir plus, consultez la documentation TIMESTAMP_TRUNC et les fonctions de date et d'heure.

Nombre de spans par code d'état

Pour afficher le nombre d'étendues avec un code d'état spécifique, exécutez la requête suivante :

SELECT
  -- Count the number of spans for each status code.
  status.code,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE status.code IS NOT NULL
GROUP BY status.code

Si vous remplacez status.code par kind, la requête précédente indique le nombre de portées pour chaque valeur de l'énumération kind. De même, si vous remplacez status.code par name, les résultats de la requête listent le nombre d'entrées pour chaque nom de span.

Calculer la durée moyenne de toutes les portées

Pour afficher la durée moyenne après avoir regroupé les données de portée par nom de portée, exécutez la requête suivante :

SELECT
  -- Group by name, and then compute the average duration for each group.
  name,
  AVG(duration_nano) AS nanosecs,
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
GROUP BY name
ORDER BY nanosecs DESC

Calculer la durée moyenne et les centiles par nom de service

La requête suivante calcule le nombre de spans et diverses statistiques pour chaque service :

SELECT
  -- Set the service name by the first non-null value.
  COALESCE(
    JSON_VALUE(resource.attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."g.co/gae/app/module"')) AS service_name,

  -- Count the number spans for each service name. Also compute statistics.
  COUNT(*) AS span_count,
  AVG(duration_nano) AS avg_duration_nano,
  MIN(duration_nano) AS min_duration_nano,
  MAX(duration_nano) AS max_duration_nano,

  -- Calculate percentiles for duration
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(50)] AS p50_duration_nano,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(95)] AS p95_duration_nano,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(99)] AS p99_duration_nano,

  -- Count the number of unique trace IDs. Also, collect up to 5 unique
  -- span names and status codes.
  COUNT(DISTINCT trace_id) AS distinct_trace_count,
  ARRAY_AGG(DISTINCT name IGNORE NULLS LIMIT 5) AS sample_span_names,
  ARRAY_AGG(DISTINCT status.code IGNORE NULLS LIMIT 5) AS sample_status_codes
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
GROUP BY service_name
ORDER BY span_count DESC

Cette section décrit deux approches que vous pouvez utiliser pour rechercher des données dans plusieurs colonnes de la vue que vous interrogez :

  • Recherches basées sur des jetons : vous spécifiez le lieu de recherche et une requête de recherche, puis vous utilisez la fonction SEARCH. Étant donné que la fonction SEARCH est soumise à des règles spécifiques concernant la recherche de données, nous vous recommandons de lire la documentation SEARCH.

  • Recherches basées sur des sous-chaînes : vous indiquez l'emplacement de la recherche, un littéral de chaîne, puis vous utilisez la fonction CONTAINS_SUBSTR. Le système effectue un test non sensible à la casse pour déterminer si le littéral de chaîne existe dans une expression. La fonction CONTAINS_SUBSTR renvoie TRUE lorsque le littéral de chaîne existe et FALSE dans le cas contraire. La valeur de la recherche doit être un littéral de type STRING, mais pas de valeur littérale NULL.

La requête suivante ne conserve que les lignes dont un champ correspond exactement à "35.193.12.15" :

SELECT
  timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID` AS t
WHERE
  -- Search data access audit logs for the IP address that matches 35.193.12.15.
  -- The use of backticks prevents the string from being tokenized.
  proto_payload IS NOT NULL AND
  log_id = "cloudaudit.googleapis.com/data_access" AND
  SEARCH(t,"`35.193.12.15`")
ORDER BY timestamp ASC
LIMIT 20

Lorsque les guillemets inversés sont omis dans la chaîne de requête, celle-ci est divisée en fonction des règles définies dans la documentation SEARCH. Par exemple, lorsque l'instruction suivante est exécutée, la chaîne de requête est divisée en quatre jetons : "35", "193", "12" et "15" :

  SEARCH(t,"35.193.12.15")

L'instruction SEARCH précédente correspond à une ligne lorsqu'un seul champ correspond aux quatre jetons. L'ordre des jetons n'a pas d'importance.

Vous pouvez inclure plusieurs instructions SEARCH dans une requête. Par exemple, dans la requête précédente, vous pouvez remplacer le filtre sur l'ID de journal par une instruction semblable à la suivante :

  SEARCH(t,"`cloudaudit.googleapis.com/data_access`")

L'instruction précédente recherche tous les champs des entrées de journal dans la vue du journal, tandis que l'instruction d'origine ne recherche que le champ log_id des entrées de journal.

Pour effectuer plusieurs recherches dans plusieurs champs, séparez les chaînes individuelles par un espace. Par exemple, l'instruction suivante correspond aux lignes dans lesquelles un champ contient "Hello World", "happy" et "days" :

  SEARCH(t,"`Hello World` happy days")

Enfin, vous pouvez rechercher des champs spécifiques au lieu de rechercher dans un tableau entier. Par exemple, l'instruction suivante ne recherche que dans les colonnes nommées text_payload et json_payload :

   SEARCH((text_payload, json_payload) ,"`35.222.132.245`")

Pour savoir comment les paramètres de la fonction SEARCH sont traités, consultez la page de référence BigQuery Fonctions de recherche.

Par exemple, la requête suivante récupère toutes les entrées de journal d'audit d'accès aux données avec une adresse IP spécifique dont les codes temporels se trouvent dans une plage de temps spécifique. Enfin, la requête trie les résultats, puis affiche les 20 plus anciens :

SELECT
  timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID` AS t
WHERE
  -- Search data access audit logs for the IP address that matches 35.193.12.15.
  -- CONTAINS_SUBSTR performs a contains-test.
  proto_payload IS NOT NULL AND
  log_id = "cloudaudit.googleapis.com/data_access" AND
  CONTAINS_SUBSTR(t,"35.193.12.15")
ORDER BY timestamp ASC
LIMIT 20

Interroger plusieurs vues

Les instructions de requête analysent une ou plusieurs tables ou expressions, et renvoient les lignes de résultats calculés. Par exemple, vous pouvez utiliser des instructions de requête pour fusionner les résultats des instructions SELECT sur différentes tables ou ensembles de données de différentes manières, puis sélectionner les colonnes à partir des données combinées.

Pour joindre des vues, les restrictions suivantes s'appliquent :

  1. Les emplacements des vues satisfont l'une des conditions suivantes :

    • Toutes les vues ont le même emplacement.
    • Toutes les vues se trouvent dans l'emplacement global ou us.
  2. Lorsque les ressources de stockage utilisent des clés de chiffrement gérées par le client (CMEK), l'une des conditions suivantes doit être remplie :

    • Les ressources de stockage qui utilisent CMEK utilisent la même clé Cloud KMS.
    • Les ressources de stockage qui utilisent CMEK ont un ancêtre commun, et cet ancêtre spécifie une clé Cloud KMS par défaut qui se trouve au même emplacement que les ressources de stockage.

    Lorsqu'une ou plusieurs ressources de stockage utilisent le CMEK, le système chiffre les données temporaires générées par la jointure avec la clé Cloud KMS commune ou la clé Cloud KMS par défaut de l'ancêtre.

Par exemple, supposons que vous ayez deux vues qui se trouvent au même emplacement. Vous pouvez ensuite joindre ces vues si l'une des conditions suivantes est remplie :

  • Les ressources de stockage n'utilisent pas CMEK.
  • Une ressource de stockage utilise CMEK, mais pas l'autre.
  • Les deux ressources de stockage utilisent le chiffrement CMEK et la même clé Cloud KMS.
  • Les deux ressources de stockage utilisent CMEK, mais avec des clés différentes. Toutefois, les ressources partagent un ancêtre qui spécifie une clé Cloud KMS par défaut située au même emplacement que les ressources de stockage.

    Par exemple, supposons que la hiérarchie des ressources pour un bucket de journaux et un bucket d'observabilité inclue la même organisation. Vous pouvez joindre des vues sur ces buckets lorsque, pour cette organisation, vous avez configuré les paramètres de ressources par défaut pour Cloud Logging et pour les buckets d'observabilité avec la même clé Cloud KMS par défaut pour l'emplacement de stockage.

Joindre deux vues de journaux par ID de trace

Pour combiner les informations de deux tables, utilisez l'un des opérateurs join :

SELECT
  -- Do an inner join on two tables by using the span ID and trace ID.
  -- Don't join only by span ID, as this field isn't globally unique.
  -- From the first view, show the timestamp, severity, and JSON payload.
  -- From the second view, show the JSON payload.
  a.timestamp, a.severity, a.json_payload, b.json_payload, a.span_id, a.trace
FROM  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_1` a
JOIN  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_2` b
ON
  a.span_id = b.span_id AND
  a.trace = b.trace
LIMIT 100

Interroger deux vues de journaux avec une instruction Union

Pour combiner les résultats d'au moins deux instructions SELECT et supprimer les lignes en double, utilisez l'opérateur UNION. Pour conserver les lignes en double, utilisez l'opérateur UNION ALL :

SELECT
  timestamp, log_name, severity, json_payload, resource, labels
-- Create a union of two log views
FROM(
  SELECT * FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_1`
  UNION ALL
  SELECT * FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_2`
)
-- Sort the union by timestamp.
ORDER BY timestamp ASC
LIMIT 100

Joindre les données de trace et de journal à l'aide de l'ID de trace

La requête suivante joint les données de journaux et de trace à l'aide des ID de délai et de trace :

SELECT
  T.trace_id,
  T.span_id,
  T.name,
  T.start_time,
  T.duration_nano,
  L.log_name,
  L.severity,
  L.json_payload
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans` AS T
JOIN
  `PROJECT_ID.LOCATION._Default._AllLogs` AS L
ON
  -- Join log and trace data by both the span ID and trace ID.
  -- Don't join only on span ID, this field isn't globally unique.
  T.span_id = L.span_id
  -- A regular expression is required because the storage format of the trace ID
  -- differs between a log view and a trace view.
  AND T.trace_id = REGEXP_EXTRACT(L.trace, r'/([^/]+)$')
WHERE T.duration_nano > 1000000
LIMIT 10

La réponse à la requête liste l'ID de trace et d'étendue, ce qui vous permet de les interroger individuellement pour obtenir plus d'informations. La liste des résultats indique également la gravité de l'entrée de journal et la charge utile JSON.

Supprimer les entrées de journal en double

L'analyse de journaux ne supprime pas les entrées de journal en double avant l'exécution d'une requête. Ce comportement est différent de celui de l'explorateur de journaux, qui supprime les entrées en double en comparant les champs "Nom du journal", "Code temporel" et "ID d'insertion".

Vous pouvez utiliser la validation au niveau des lignes pour supprimer les entrées de journaux en double.

Pour en savoir plus, consultez Résoudre les problèmes : des entrées de journaux en double figurent dans les résultats de l'analyse des journaux.

Étapes suivantes

Pour obtenir la documentation de référence SQL ou d'autres exemples, consultez les documents suivants :