Diviser les entrées du journal d'audit

Ce document explique comment Cloud Logging divise les entrées de journaux d'audit de très grande taille et explique comment réassembler ces journaux d'audit fractionnés.

Lorsqu'une seule entrée de journal d'audit dépasse la limite de taille, Cloud Logging divise cette entrée et répartit 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 individuelles ne contiennent pas tous les champs du journal d'audit d'origine.

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

Les entrées de journal fractionnées contiennent des informations sur l'entrée d'origine à partir de laquelle elles ont été divisées. Si une entrée de journal contient un champ split, elle résulte de la division d'une entrée de journal d'origine plus importante. 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 divisées à partir d'une entrée de journal d'origine commune. La valeur de ce champ est la même pour toutes les entrées divisées à partir 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 du fractionnement 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 divisées à partir de l'entrée de journal d'origine.

Comment une entrée de journal est-elle fractionné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 d'audit 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 divisés 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 fractionné, mais n'est pas l'un des types de champs fractionnés, il n'est présent que dans l'un des journaux fractionnés.

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

Pour obtenir un exemple de division d'une entrée de longue durée, consultez la section Exemple de entrée de journal 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, cette liste peut être divisée et distribuée sur plusieurs entrées de journal fractionné.

Par exemple, la liste de valeurs ["foo", "bar", "baz"] peut être divisée en deux listes: ["foo", "ba"] et ["", "r", "baz"]. La première liste correspond à l'entrée dont le champ split.index est défini sur 0, et la deuxième liste à l'entrée dont le champ split.index est défini sur 1. La deuxième liste commence par une chaîne vide pour maintenir les positions des éléments dans la liste et pour indiquer que les éléments ayant la même position dans les différentes listes doivent être joints. Dans l'exemple, ba est le deuxième élément de liste dans 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 uniques

Lorsque des champs Struct et string non répétés et volumineux sont fractionnés, ces champs sont traités comme suit:

  • Un champ string est fractionné au niveau des caractères et non au niveau de l'octet. Les caractères à plusieurs octets ne sont donc pas modifiés.

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

Réassembler l'entrée de journal fractionné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 reconstitué.

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

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

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

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

  4. Après avoir itéré dans les champs fractionnés, effacez LogEntry.split du journal reconstitué.

  5. Supprimez le suffixe .0 du 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 faisant partie d'une division, exécutez la requête suivante:

split:*

Filtrer les journaux d'audit fractionné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 répartition des entrée de journal

L'exemple suivant montre une entrée de journal d'audit avant d'être divisée en quatre nouvelles entrées de journal. Les nouvelles entrées montrent comment les différents champs sont gérés dans l'opération de division.

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 la 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 un uid et une totalSplits pour 4. Chaque entrée a une valeur split.index de 0, 1, 2 ou 3, ce qui indique l'ordre des entrées de journal fractionnées.

Fractionner l'entrée de journal, index 0

Voici la première entrée de journal fractionnée, avec la 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 ",
    }
  }
}

Fractionner l'entrée de journal, index 1

Voici l'entrée de journal fractionnée suivante, avec la 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 ",
      }
    }
  }
}

Fractionner l'entrée de journal, index 2

Voici l'entrée de journal fractionnée suivante, avec la 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.
      ]
    }
  }
}

Fractionner l'entrée de journal, index 3

Voici la dernière entrée de journal fractionné, avec la 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"},
      ]
    }
  }
}