Diviser les entrées du journal d'audit

Ce document explique comment Cloud Logging divise les entrées de journal d'audit trop volumineuses et fournit des conseils pour les réassembler.

Lorsqu'une seule entrée de journal d'audit dépasse la limite de taille, Cloud Logging la divise et distribue les données contenues dans l'entrée de journal d'audit d'origine entre plusieurs entrées. Les utilisateurs peuvent souhaiter réassembler les journaux d'audit fractionnés, car les entrées de journal fractionnées ne contiennent pas tous les champs du journal d'audit d'origine.

Reconnaître les entrées de journal d'audit fractionnées

Les entrées de journal fractionnées contiennent des informations sur l'entrée d'origine à partir de laquelle elles ont été fractionnées. Si une entrée de journal contient un champ split, elle résulte de la scission d'une entrée de journal d'origine plus grande. Le champ split est un objet LogSplit qui contient les informations nécessaires pour identifier les entrées de journal fractionnées associées.

Chaque entrée de journal fractionnée contient les champs suivants:

  • split.uid: identifiant unique du groupe d'entrées de journal qui ont été divisées à partir d'une entrée de journal d'origine commune. La valeur de ce champ est identique pour toutes les entrées issues de l'entrée de journal d'origine.

  • split.index: position de cette entrée dans la série d'entrées fractionnées. La première entrée de la division a l'index 0. split.index est également ajouté au champ LogEntry.insertId.

  • split.totalSplits: nombre d'entrées de journal dans lesquelles l'entrée de journal d'origine a été divisée. La valeur de ce champ est la même pour toutes les entrées issues de l'entrée de journal d'origine.

Comment une entrée de journal est-elle divisée ?

Lorsqu'une entrée de journal d'audit surdimensionnée est divisée, les champs sont répartis entre les entrées de journal divisées résultantes comme suit:

  • Tous les champs, à l'exception du champ protoPayload, sont dupliqués dans chaque entrée fractionnée.

  • Les sous-champs protoPayload suivants peuvent être répartis sur plusieurs entrées:

    • protoPayload.metadata
    • protoPayload.request
    • protoPayload.response
  • Tous les autres sous-champs protoPayload sont inclus dans toutes les entrées fractionnées.

  • Pour les sous-champs protoPayload.metadata, protoPayload.request et protoPayload.response, les types de champs suivants peuvent être répartis sur plusieurs entrées:

Si un champ est membre d'un champ séparable, mais qu'il ne fait pas partie des types de champs séparables, il n'est présent que dans l'un des journaux de fractionnement.

Par exemple, un champ booléen dans le sous-champ protoPayload.request ne peut apparaître que dans une seule entrée de journal fractionnée, mais le contenu d'un champ de chaîne dans le sous-champ protoPayload.request peut être réparti sur plusieurs entrées de journal fractionnées.

Pour voir comment une entrée longue est fractionnée, consultez la section Exemple de fractionnement d'une entrée de journal.

Champs répétés avec de nombreuses valeurs

Lorsque la valeur du champ protoPayload.metadata, protoPayload.request ou protoPayload.response contient une liste de valeurs répétées, la liste peut être divisée et répartie sur plusieurs entrées de journal fractionnées.

Par exemple, la liste de valeurs ["foo", "bar", "baz"] peut être scindée en deux listes: ["foo", "ba"] et ["", "r", "baz"]. La première liste correspond à l'entrée avec le split.index de 0, et la deuxième liste correspond à l'entrée avec le split.index de 1. La deuxième liste commence par une chaîne vide pour conserver les positions des éléments dans la liste et indiquer que les éléments occupant les mêmes positions dans les différentes listes doivent être joints. Dans l'exemple, ba est le deuxième élément de liste de l'entrée 0, et r est le deuxième élément de liste de l'entrée 1. Ils sont donc recombinés dans l'ordre bar lors du réassemblage de la liste d'origine.

Champs volumineux et non répétés

Lorsque des champs Struct et string volumineux et non répétés sont divisés, ils sont gérés comme suit:

  • Un champ string est divisé au niveau des caractères et non au niveau des octets. Par conséquent, les caractères multi-octets ne sont pas modifiés.

  • LogEntry.split.index contrôle l'ordre des contenus des champs fractionnés et non répétés.

Recomposer une entrée de journal divisée

Pour réassembler un ensemble de journaux fractionnés, procédez comme suit:

  1. Triez l'ensemble des journaux d'audit fractionnés par LogEntry.split.index dans l'ordre croissant.

  2. Créez une copie du premier journal fractionné, où LogEntry.split.index == 0. Cette copie correspond au début du journal réassemblé.

  3. Pour les autres entrées de journal, itérez sur tous les champs séparables de protoPayload et procédez comme suit pour chaque champ:

    1. Si le champ existe déjà dans le journal réassemblé, ajoutez le contenu de ce champ au journal réassemblé.

    2. Si le champ n'existe pas dans le journal réassemblé, copiez-le dans le journal réassemblé.

      Lors de la division, les champs répétés conservent l'index de leurs éléments. Vous pouvez donc appliquer ces étapes au niveau de l'élément lorsque vous réassemblez un champ répété.

  4. Après avoir itéré sur les champs séparables, effacez LogEntry.split du journal réassemblé.

  5. Supprimez le suffixe .0 de LogEntry.insert_id du journal réassemblé.

Exemples de requêtes

Pour rechercher toutes les entrées de journal qui ont été divisées à partir de la même entrée de journal d'origine, exécutez la requête suivante dans l'explorateur de journaux, en remplaçant la variable UID par la valeur souhaitée:

split.uid="UID"

Exemple :

split.uid="abc123"

Pour rechercher toutes les entrées de journal qui font partie d'une division, exécutez la requête suivante:

split:*

Filtrer les journaux d'audit divisés

Vous pouvez exclure tous les journaux d'audit fractionnés d'une requête à l'aide du filtre suivant:

split.totalSplits = 0

Vous pouvez également n'inclure que la première entrée d'un journal d'audit fractionné et exclure le reste des entrées à l'aide du filtre suivant:

split.index = 0

Exemple de fractionnement d'une entrée de journal

L'exemple suivant montre une entrée de journal d'audit avant qu'elle ne soit divisée en quatre nouvelles entrées de journal. Les nouvelles entrées montrent comment différents champs sont gérés dans l'opération de fractionnement.

Entrée de journal d'audit surdimensionnée avant la division

{
  "insertId": "567",
  "logName": "projects/1234/logs/cloudaudit.googleapis.com%2Fdata_access",
  "resource": {
    "type": "audited_resource"
  },
  "protoPayload": {
    "serviceName": "example.googleapis.com",
    "methodName": "google.cloud.example.ExampleMethod",
    "resourceName": "projects/1234/resources/123",
    "status": {
      "code": 0
    },
    "authenticationInfo": {
      "principalEmail": "user@example_company.com"
    },
    "authorizationInfo": [
      {
        "resource": "example.googleapis.com/projects/1234/resources/123",
        "permission": "examples.get",
        "granted": "true"
      }
    ],
    "request" {
      "boolField": true,
      "numberField": 123,
      "stringField": "Very long string that needs 2 log entries.",
      "structField": {
        "nestedNumberField": 1337,
        "nestedStringField": "Another long string that needs 2 log entries.",
      },
      "listField" [
        {"value": "short 1"},
        {"value": "Yet another long string."},
        {"value": "short 2"},
        {"value": "short 3"},
      ]
    }
  }
}

Entrée de journal d'audit surdimensionnée après division

L'entrée de journal d'origine est divisée en entrées suivantes. Notez que chaque entrée inclut l'objet split avec une valeur uid et totalSplits de 4. Chaque entrée a une valeur split.index de 0, 1, 2 ou 3, qui indique l'ordre des entrées de journal fractionnées.

Entrée de journal fractionnée, index 0

Voici la première entrée de journal de fractionnement, avec une valeur split.index de 0.

{
  "insertId": "567.0",
  "logName": "projects/1234/logs/cloudaudit.googleapis.com%2Fdata_access",
  "resource": {
    "type": "audited_resource"
  },
  "split": { 
    "uid": "789+2022-02-22T12:22:22.22+05:00",
    "index": 0,
    "totalSplits": 4,
  },
  "protoPayload": {
    // The following fields are included in all split entries
    "serviceName": "example.googleapis.com",
    "methodName": "google.cloud.example.ExampleMethod",
    "resourceName": "projects/1234/resources/123",
    "status": {
      "code": 0
    },
    "authenticationInfo": {  // small size; included in all split entries
      "principalEmail": "user@example_company.com"
    },
   // The following field is included in this split entry only.
   "authorizationInfo": [
      {
        "resource": "spanner.googleapis.com/projects/1234/datasets/123",
        "permission": "databases.read",
        "granted": "true"
      }
    ],
    // The following field is split across all the split entries
    "request" { 
      // boolField and numberField can only be in one split.
      "boolField": true,
      "numberField": 123,
      // Split with the next LogEntry.
      "stringField": "Very long string that ",
    }
  }
}

Entrée de journal fractionnée, index 1

Voici la prochaine entrée de journal de fractionnement, avec une valeur split.index de 1.

{
  "insertId": "567.1",
  "logName": "projects/1234/logs/cloudaudit.googleapis.com%2Fdata_access",
  "resource": {
    "type": "audited_resource"
  },
  "split": { 
    "uid": "567+2022-02-22T12:22:22.22+05:00",
    "index": 1,
    "totalSplits": 4,
  },
  "protoPayload": { 
    "serviceName": "example.googleapis.com",
    "methodName": "google.cloud.example.ExampleMethod",
    "resourceName": "projects/1234/resources/123",
    "status": {
      "code": 0
    },
    "authenticationInfo": {
      "principalEmail": "user@example_company.com"
    },
    "request" { 
      // boolField and numberField aren't present
      // Continued from the previous entry.
      "stringField": "needs 2 log entries.",
      "structField": { 
        "nestedNumberField": 1337,
        // Split with the next LogEntry.
        "nestedStringField": "Another long string ",
      }
    }
  }
}

Entrée de journal fractionnée, index 2

Voici la prochaine entrée de journal de fractionnement, avec une valeur split.index de 2.

{
  "insertId": "567.2",
  "logName": "projects/1234/logs/cloudaudit.googleapis.com%2Fdata_access",
  "resource": {
    "type": "audited_resource"
  },
  "split": { 
    "uid": "567+2022-02-22T12:22:22.22+05:00",
    "index": 2,
    "totalSplits": 4,
  },
  "protoPayload": { 
    "serviceName": "example.googleapis.com",
    "methodName": "google.cloud.example.ExampleMethod",
    "resourceName": "projects/1234/resources/123",
    "status": {
      "code": 0
    },
    "authenticationInfo": {
      "principalEmail": "user@example_company.com"
    },
    request { 
      "structField": { 
        // Continued from the previous entry.
        "nestedStringField": "that needs 2 log entries.",
      }
      "listField" [ 
         {"value": "short 1"},
         {"value": "Yet another "}, // Split with the next LogEntry.
        // Missing two values, split with the next LogEntry.
      ]
    }
  }
}

Entrée de journal fractionnée, index 3

Voici l'entrée de journal de division finale, avec une valeur split.index de 3.

{
  "insertId": "567.3",
  "logName": "projects/1234/logs/cloudaudit.googleapis.com%2Fdata_access",
  "resource": {
    "type": "audited_resource"
  },
  "split": { 
    "uid": "567+2022-02-22T12:22:22.22+05:00",
    "index": 3,
    "totalSplits": 4,
  },
  "protoPayload": { 
    "serviceName": "example.googleapis.com",
    "methodName": "google.cloud.example.ExampleMethod",
    "resourceName": "projects/1234/resources/123",
    "status": {
      "code": 0
    },
    "authenticationInfo": {
      "principalEmail": "user@example_company.com"
    },
    "request" { 
      "listField" [ 
        {}, // Padding to ensure correct positioning of elements in split repeated fields.
         {"value": "long string."}, // Continuation of the second repeated field.
         {"value": "short 2"},
         {"value": "short 3"},
      ]
    }
  }
}