拆分审核日志条目

本文档介绍了 Cloud Logging 如何拆分超大的审核日志条目,并介绍了如何重新组合这些拆分审核日志。

当单个审核日志条目超过大小限制时,Cloud Logging 会拆分该条目,并将原始审核日志条目中包含的数据分布到多个条目中。用户可能需要重新组合拆分审核日志,因为各个拆分日志条目不包含原始审核日志中的所有字段。

识别拆分的审核日志条目

拆分日志条目包含有关拆分它们的原始条目的信息。如果日志条目包含 split 字段,则该条目是拆分较大的原始日志条目的结果。split 字段是一个 LogSplit 对象,其中包含标识相关拆分日志条目所需的信息。

每个拆分日志条目包含以下字段:

  • split.uid:从共同的原始日志条目拆分的那组日志条目的唯一标识符。对于从原始日志条目拆分的所有条目,此字段的值都相同。

  • split.index:此条目在一系列分屏条目中的位置。分块中第一个条目的索引为 0split.index 也会附加到 LogEntry.insertId 字段。

  • split.totalSplits:原始日志条目被拆分的日志条目数。对于从原始日志条目拆分的所有条目,此字段的值都相同。

日志条目的拆分方式

拆分过大的审核日志条目时,这些字段会在生成的拆分日志条目之间分布,如下所示:

  • protoPayload 字段之外的所有字段都会复制到每个拆分条目中。

  • 以下 protoPayload 子字段可拆分为多个条目:

    • protoPayload.metadata
    • protoPayload.request
    • protoPayload.response
  • 所有其他 protoPayload 子字段都包含在所有分屏条目中。

  • 对于 protoPayload.metadataprotoPayload.requestprotoPayload.response 子字段,以下字段类型可以拆分为多个条目:

如果某个字段是可拆分字段的成员,但不属于可拆分字段类型,则它仅出现在其中一个拆分日志中。

例如,protoPayload.request 子字段中的布尔值字段只能出现在一个拆分日志条目中,但 protoPayload.request 子字段中的字符串字段可以将其内容拆分到多个拆分日志条目中。

如需查看如何拆分长条目的示例,请参阅日志条目拆分示例

包含多个值的重复字段

protoPayload.metadataprotoPayload.requestprotoPayload.response 字段的值包含重复值列表时,该列表可能会被分解并分布到多个拆分日志条目中。

例如,值 ["foo", "bar", "baz"] 的列表可以拆分为 2 个列表:["foo", "ba"] 和 ["", "r", "baz"]。第一个列表是 split.index0 的条目,第二个列表位于 split.index1 的条目中。第二个列表以空字符串开头,用来保持列表中元素的位置,并指示不同列表中相同位置的元素必须连接在一起。在本例中,ba 是条目 0 中的第二个列表元素,r 是条目 1 中的第二个列表元素,因此在重新组装原始列表时,它们会按 bar 顺序重新组合。

大型非重复字段

拆分较大的非重复 Structstring 字段时,这些字段的处理方式如下:

  • string 字段在字符级别而不是字节级别进行拆分。因此,多字节字符不会改变。

  • LogEntry.split.index 用于控制拆分的非重复字段的内容顺序。

重新组合拆分日志条目

如需重新组合一组拆分日志,请完成以下步骤:

  1. LogEntry.split.index 对拆分审核日志集进行升序排序。

  2. 创建第一个拆分日志的副本,其中 LogEntry.split.index == 0。此副本是重新组合的日志的开头。

  3. 对于其余日志条目,遍历 protoPayload 的所有可拆分字段,并针对每个字段完成以下步骤:

    1. 如果重新组合的日志中已存在该字段,请将该字段的内容附加到重新组合的日志中。

    2. 如果重新组合的日志中不存在该字段,请将该字段复制到重新组合的日志中

      拆分时,重复字段会保留其元素的索引,因此您可以在重新组合重复字段时在元素级别应用这些步骤。

  4. 遍历可拆分字段后,清除重新组合日志的 LogEntry.split

  5. 从重组的日志的 LogEntry.insert_id 中移除 .0 后缀。

查询示例

如需查找从同一原始日志条目拆分的所有日志条目,请在日志浏览器中运行以下查询,将 UID 变量替换为所需的值:

split.uid="UID"

例如:

split.uid="abc123"

如需查找属于任何分块的所有日志条目,请运行以下查询:

split:*

过滤掉拆分审核日志

您可以使用以下过滤条件从查询中排除所有拆分审核日志:

split.totalSplits = 0

您还可以仅包含拆分审核日志的第一个条目,并使用以下过滤条件排除其余条目:

split.index = 0

日志条目拆分示例

以下示例展示了审核日志条目在拆分为四个新日志条目之前的示例。新条目展示了在拆分操作中如何处理不同字段。

拆分前的超大审核日志条目

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

拆分后的超大审核日志条目

原始日志条目会拆分为以下条目。请注意,每个条目都包含 split 对象,该对象具有 uidtotalSplits 值为 4。每个条目的 split.index 值为 0123,指示拆分日志条目的顺序。

拆分日志条目,索引 0

这是第一个拆分日志条目,split.index 值为 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 ",
    }
  }
}

拆分日志条目,索引 1

下面是下一个拆分日志条目,split.index 值为 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 ",
      }
    }
  }
}

拆分日志条目,索引 2

下面是下一个拆分日志条目,split.index 值为 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.
      ]
    }
  }
}

拆分日志条目,索引 3

下面是最终的拆分日志条目,split.index 值为 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"},
      ]
    }
  }
}