Divida as entradas do registo de auditoria

Este documento descreve como o Cloud Logging divide as entradas de registo de auditoria demasiado grandes e fornece orientações sobre como voltar a montar estes registos de auditoria divididos.

Quando uma única entrada do registo de auditoria excede o limite de tamanho, o Cloud Logging divide essa entrada e distribui os dados contidos na entrada do registo de auditoria original por várias entradas. Os utilizadores podem querer voltar a montar os registos de auditoria divididos, uma vez que as entradas de registo divididas individuais não contêm todos os campos do registo de auditoria original.

Reconhecer entradas de registos de auditoria divididas

As entradas de registo divididas contêm informações sobre a entrada original a partir da qual foram divididas. Se uma entrada de registo contiver um campo split, significa que a entrada é o resultado da divisão de uma entrada de registo original maior. O campo split é um objeto LogSplit que contém as informações necessárias para identificar as entradas de registo divididas relacionadas.

Cada entrada de registo dividido contém os seguintes campos:

  • split.uid: um identificador exclusivo para o grupo de entradas de registo que foram divididas a partir de uma entrada de registo original comum. O valor deste campo é o mesmo para todas as entradas divididas a partir da entrada de registo original.

  • split.index: a posição desta entrada na série de entradas divididas. A primeira entrada da divisão tem o índice 0. split.index também é anexado ao campo LogEntry.insertId.

  • split.totalSplits: o número de entradas de registo em que a entrada de registo original foi dividida. O valor deste campo é o mesmo para todas as entradas divididas a partir da entrada de registo original.

Como uma entrada de registo é dividida

Quando uma entrada de registo de auditoria demasiado grande é dividida, os campos são distribuídos pelas entradas de registo divididas resultantes da seguinte forma:

  • Todos os campos, exceto o campo protoPayload, são duplicados em cada entrada dividida.

  • Os seguintes subcampos protoPayload podem ser divididos em várias entradas:

    • protoPayload.metadata
    • protoPayload.request
    • protoPayload.response
  • Todos os outros subcampos protoPayload estão incluídos em todas as entradas divididas.

  • Para os subcampos protoPayload.metadata, protoPayload.request e protoPayload.response, os seguintes tipos de campos podem ser divididos em várias entradas:

Se um campo for membro de um campo divisível, mas não for um dos tipos de campos divisíveis, só está presente num dos registos divididos.

Por exemplo, um campo booleano no subcampo protoPayload.request só pode aparecer numa entrada de registo dividida, mas um campo de string no subcampo protoPayload.request pode ter o respetivo conteúdo dividido em várias entradas de registo divididas.

Para ver um exemplo de como uma entrada longa é dividida, consulte o Exemplo de divisão de entrada do registo.

Campos repetidos com muitos valores

Quando o valor do campo protoPayload.metadata, protoPayload.request ou protoPayload.response contém uma lista de valores repetidos, a lista pode ser dividida e distribuída por várias entradas de registo divididas.

Por exemplo, a lista de valores ["foo", "bar", "baz"] pode ser dividida em 2 listas: ["foo", "ba"] e ["", "r", "baz"]. A primeira lista é a entrada com o split.index de 0 e a segunda lista está na entrada com o split.index de 1. A segunda lista começa com uma string vazia para manter as posições dos elementos na lista e indicar que os elementos nas mesmas posições nas diferentes listas têm de ser unidos. No exemplo, ba é o segundo elemento da lista na entrada 0 e r é o segundo elemento da lista na entrada 1, pelo que são recombinados na ordem bar quando a lista original é remontada.

Campos grandes não repetidos

Quando os campos Struct e string grandes e não repetidos são divididos, estes campos são processados da seguinte forma:

  • Um campo string é dividido ao nível do caráter e não ao nível do byte. Assim, os carateres multibyte não são alterados.

  • LogEntry.split.index controla a ordem dos conteúdos de campos divididos que não se repetem.

Volte a montar a entrada do registo dividida

Para voltar a montar um conjunto de registos divididos, conclua os seguintes passos:

  1. Ordene o conjunto de registos de auditoria divididos por LogEntry.split.index por ordem ascendente.

  2. Crie uma cópia do primeiro registo de divisão, onde LogEntry.split.index == 0. Esta cópia é o início do registo remontado.

  3. Para as restantes entradas do registo, itere todos os campos divisíveis de protoPayload e conclua os seguintes passos para cada campo:

    1. Se o campo já existir no registo remontado, anexe o conteúdo desse campo ao registo remontado.

    2. Se o campo não existir no registo remontado, copie esse campo para o registo remontado

      Quando divididos, os campos repetidos preservam o índice dos respetivos elementos, pelo que pode aplicar estes passos ao nível do elemento quando voltar a montar um campo repetido.

  4. Após iterar os campos divisíveis, limpe LogEntry.split do registo remontado.

  5. Remova o sufixo .0 do LogEntry.insert_id do registo remontado.

Consultas de exemplo

Para encontrar todas as entradas de registo que foram divididas a partir da mesma entrada de registo original, execute a seguinte consulta no Explorador de registos, depois de substituir a variável UID pelo valor escolhido:

split.uid="UID"

Por exemplo:

split.uid="abc123"

Para encontrar todas as entradas do registo que fazem parte de qualquer divisão, execute a seguinte consulta:

split:*

Filtre registos de auditoria divididos

Pode excluir todos os registos de auditoria de divisão de uma consulta através do seguinte filtro:

split.totalSplits = 0

Também pode incluir apenas a primeira entrada de um registo de auditoria dividido e excluir as restantes entradas através do seguinte filtro:

split.index = 0

Exemplo de divisão de entrada do registo

O exemplo seguinte mostra uma entrada do registo de auditoria antes de ser dividida em quatro novas entradas do registo. As novas entradas mostram como os diferentes campos são processados na operação de divisão.

Entrada de registo de auditoria demasiado grande antes da divisão

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

Entrada de registo de auditoria demasiado grande após a divisão

A entrada de registo original é dividida nas seguintes entradas. Tenha em atenção que cada entrada inclui o objeto split com um valor uid e um valor totalSplits de 4. Cada entrada tem um valor split.index de 0, 1, 2 ou 3, que indica a ordem das entradas do registo dividido.

Entrada do registo dividida, índice 0

Segue-se a primeira entrada do registo dividido, com um valor 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 ",
    }
  }
}

Entrada do registo dividida, índice 1

Segue-se a entrada do registo de divisão seguinte, com um valor de split.index1.

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

Entrada do registo dividida, índice 2

Segue-se a entrada do registo de divisão seguinte, com um valor de split.index2.

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

Entrada do registo dividida, índice 3

Segue-se a entrada do registo de divisão final, com um valor de 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"},
      ]
    }
  }
}