Suddividi le voci degli audit log

Questo documento descrive come Cloud Logging suddivide le voci degli audit log di grandi dimensioni e fornisce indicazioni su come riassemblare questi audit log suddivisi.

Quando una singola voce dell'audit log supera il limite delle dimensioni, Cloud Logging suddivide la voce e distribuisce i dati contenuti nella voce dell'audit log originale tra più voci. Gli utenti potrebbero voler riassemblare gli audit log suddivisi poiché le singole voci di log suddivisi non contengono tutti i campi dell'audit log originale.

Riconoscimento delle voci degli audit log suddivisi

Le voci di log suddivise contengono informazioni sulla voce originale da cui sono state suddivise. Se una voce di log contiene un campo split, la voce è il risultato della suddivisione di una voce di log originale di dimensioni maggiori. Il campo split è un oggetto LogSplit contenente le informazioni necessarie per identificare le voci di log suddivise correlate.

Ogni voce di log suddivisa contiene i seguenti campi:

  • split.uid: un identificatore univoco per il gruppo di voci di log suddivise da una voce di log originale comune. Il valore di questo campo è lo stesso per tutte le voci suddivise dalla voce di log originale.

  • split.index: la posizione della voce nella serie di voci suddivise. La prima voce della suddivisione ha l'indice 0. Viene aggiunto anche split.index al campo LogEntry.insertId.

  • split.totalSplits: il numero di voci di log in cui è stata suddivisa la voce di log originale. Il valore di questo campo è lo stesso per tutte le voci suddivise dalla voce di log originale.

Come viene suddivisa una voce di log

Quando una voce di audit log di grandi dimensioni viene suddivisa, i campi vengono distribuiti tra le voci di log suddivise risultanti, come segue:

  • Tutti i campi tranne il campo protoPayload vengono duplicati in ogni voce di suddivisione.

  • I seguenti protoPayload sottocampi possono essere suddivisi in più voci:

    • protoPayload.metadata
    • protoPayload.request
    • protoPayload.response
  • Tutti gli altri sottocampi protoPayload sono inclusi in tutte le voci suddivise.

  • Per i sottocampi protoPayload.metadata, protoPayload.request e protoPayload.response, i seguenti tipi di campo possono essere suddivisi in più voci:

Se un campo fa parte di un campo dividebile ma non è uno dei tipi di campo suddivisibili, allora è presente solo in uno dei log di suddivisione.

Ad esempio, un campo booleano nel sottocampo protoPayload.request può apparire solo in una sola voce di log suddivisa, mentre il contenuto di un campo stringa nel sottocampo protoPayload.request può essere suddiviso in più voci di log suddivise.

Per un esempio di suddivisione di una voce lunga, consulta Esempio di voce di log log.

Campi ripetuti con molti valori

Quando il valore dei campi protoPayload.metadata, protoPayload.request o protoPayload.response contiene un elenco di valori ripetuti, l'elenco potrebbe essere suddiviso e distribuito tra più voci di log suddivise.

Ad esempio, l'elenco di valori ["foo", "bar", "baz"] potrebbe essere suddiviso in 2 elenchi: ["foo", "ba"] e ["", "r", "baz"]. Il primo elenco è la voce con split.index di 0, mentre il secondo è la voce con split.index di 1. Il secondo elenco inizia con una stringa vuota per mantenere le posizioni degli elementi nell'elenco e per indicare che gli elementi che si trovano nelle stesse posizioni nei diversi elenchi devono essere uniti. Nell'esempio, ba è il secondo elemento di elenco nella voce 0 e r è il secondo elemento di elenco nella voce 1, pertanto vengono ricombinati nell'ordine bar durante il riassemblaggio dell'elenco originale.

Campi grandi non ripetuti

Quando vengono suddivisi i campi Struct e string non ripetuti e di grandi dimensioni, questi vengono gestiti come segue:

  • Un campo string è suddiviso a livello di carattere e non a livello di byte. Pertanto, i caratteri multibyte non vengono alterati.

  • LogEntry.split.index controlla l'ordine dei contenuti dei campi suddivisi e non ripetuti.

Riassembla voce di log suddivisa

Per riassemblare un set di log suddivisi, segui questi passaggi:

  1. Ordina il set di audit log suddivisi per LogEntry.split.index in ordine crescente.

  2. Crea una copia del primo log suddiviso, dove LogEntry.split.index == 0. Questa copia è l'inizio del log riassemblato.

  3. Per le restanti voci di log, ripeti tutti i campi suddivisibili di protoPayload e completa i seguenti passaggi per ogni campo:

    1. Se il campo esiste già nel log riassemblato, aggiungine il contenuto nel log riassemblato.

    2. Se il campo non esiste nel log riassemblato, copialo nel log riassemblato.

      Una volta suddivisi, i campi ripetuti conservano l'indice degli elementi, quindi puoi applicare questi passaggi a livello di elemento durante il riassemblaggio di un campo ripetuto.

  4. Dopo aver eseguito l'iterazione nei campi suddivisibili, cancella LogEntry.split del log riassemblato.

  5. Rimuovi il suffisso .0 da LogEntry.insert_id del log riassemblato.

Query di esempio

Per trovare tutte le voci di log suddivise dalla stessa voce di log originale, esegui la seguente query in Esplora log, sostituendo la variabile UID con il valore desiderato:

split.uid="UID"

Ad esempio:

split.uid="abc123"

Per trovare tutte le voci di log che fanno parte di qualsiasi suddivisione, esegui la query seguente:

split:*

Filtrare gli audit log suddivisi

Puoi escludere tutti gli audit log suddivisi da una query utilizzando il seguente filtro:

split.totalSplits = 0

Puoi anche includere solo la prima voce di un audit log suddiviso ed escludere le altre voci utilizzando il seguente filtro:

split.index = 0

Esempio di suddivisione voce di log

L'esempio seguente mostra una voce dell'audit log prima che venga suddivisa in quattro nuove voci di log. Le nuove voci mostrano come vengono gestiti i diversi campi nell'operazione di suddivisione.

Voce dell'audit log di grandi dimensioni prima della suddivisione

{
  "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"},
      ]
    }
  }
}

Voce di audit log di grandi dimensioni dopo la suddivisione

La voce di log originale è suddivisa nelle seguenti voci. Tieni presente che ogni voce include l'oggetto split con uid e un valore totalSplits pari a 4. Ogni voce ha un valore split.index pari a 0, 1, 2 o 3, che indica l'ordine delle voci di log suddivise.

Voce di log suddivisa, indice 0

Ecco la prima voce di log suddivisa, con un valore split.index pari a 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 ",
    }
  }
}

Suddividi voce di log, indice 1

Ecco la voce di log suddivisa successiva, con un valore split.index pari a 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 ",
      }
    }
  }
}

Suddividi voce di log, indice 2

Ecco la voce di log suddivisa successiva, con un valore split.index pari a 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.
      ]
    }
  }
}

Voce di log suddivisa, indice 3

Ecco l'ultima voce di log suddivisa, con un valore split.index pari a 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"},
      ]
    }
  }
}