감사 로그 항목 분할

이 문서에서는 Cloud Logging이 크기가 큰 감사 로그 항목을 분할하는 방법과 분할된 감사 로그를 재조합하는 방법을 설명합니다.

단일 감사 로그 항목이 크기 제한을 초과하면 Cloud Logging은 해당 항목을 분할하여 원본 감사 로그 항목에 포함된 데이터를 여러 항목에 분산합니다. 분할된 개별 로그 항목에 원본 감사 로그의 모든 필드가 포함되어 있지 않기 때문에 사용자는 분할 감사 로그를 재조합하기를 원할 수 있습니다.

분할 감사 로그 항목 인식

분할 로그 항목에는 분할된 원본 항목에 대한 정보가 포함되어 있습니다. 로그 항목에 split 필드가 포함된 경우 더 큰 원본 로그 항목을 분할한 결과입니다. split 필드는 관련된 분할 로그 항목을 식별하는 데 필요한 정보가 포함된 LogSplit 객체입니다.

각 분할 로그 항목에는 다음 필드가 포함됩니다.

  • split.uid: 공통 원본 로그 항목에서 분할된 로그 항목 그룹의 고유 식별자입니다. 이 필드의 값은 원본 로그 항목에서 분할된 모든 항목에서 동일합니다.

  • split.index: 일련의 분할 항목에서 이 항목의 위치입니다. 분할에서 첫 번째 항목에는 0 색인이 포함됩니다. split.indexLogEntry.insertId 필드에 추가됩니다.

  • split.totalSplits: 원본 로그 항목에서 분할된 로그 항목의 수입니다. 이 필드의 값은 원본 로그 항목에서 분할된 모든 항목에서 동일합니다.

로그 항목 분할 방법

크기가 큰 감사 로그 항목이 분할되면 필드는 다음과 같이 분할 로그 항목들 사이에서 분산됩니다.

  • protoPayload 필드를 제외한 모든 필드는 각 분할 항목에 복제됩니다.

  • 다음 protoPayload 하위 필드는 여러 항목으로 분할될 수 있습니다.

    • protoPayload.metadata
    • protoPayload.request
    • protoPayload.response
  • 다른 모든 protoPayload 하위 필드는 다른 모든 분할 항목에 포함됩니다.

  • protoPayload.metadata, protoPayload.request, protoPayload.response 하위 필드의 경우 다음 필드 유형을 여러 항목 사이에 분할할 수 있습니다.

필드가 분할 가능한 필드 구성원이지만 분할 가능한 필드 유형에 속하지 않는 경우, 해당 필드는 분할 로그 중 하나에만 존재하게 됩니다.

예를 들어 protoPayload.request 하위 필드의 부울 필드는 하나의 분할 로그 항목에만 나타날 수 있지만 protoPayload.request 하위 필드의 문자열 필드는 해당 콘텐츠가 여러 분할 로그 항목들 사이에 분할될 수 있습니다.

긴 항목이 분할되는 방법에 대한 예시는 로그 항목 분할 예시를 참조하세요.

많은 값이 있는 반복 필드

protoPayload.metadata, protoPayload.request, protoPayload.response 필드의 값에 반복되는 값 목록이 포함된 경우 목록을 분할하여 여러 분할 로그 항목들 사이에 분산할 수 있습니다.

예를 들어 ["foo", "bar", "baz"] 값 목록은 ["foo", "ba"] 및 ["", "r", "baz]의 2개 목록으로 분할될 수 있습니다. 첫 번째 목록은 split.index0인 항목이고 두 번째 목록은 split.index1인 항목에 있습니다. 두 번째 목록은 빈 문자열로 시작하여 목록의 요소 위치를 유지하고 서로 다른 목록의 동일한 위치에 있는 요소가 함께 결합되어야 함을 나타냅니다. 이 예시에서 ba0 항목의 두 번째 목록 요소이고 r1 항목의 두 번째 목록 요소이므로 원래 목록을 다시 조합할 때 순서 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

로그 항목 분할 예시

다음 예시에서는 4개의 새로운 로그 항목으로 분할되기 전의 감사 로그 항목을 보여줍니다. 새 항목은 분할 작업에서 여러 필드가 처리되는 방법을 보여줍니다.

분할 전 과도하게 큰 감사 로그 항목

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

분할 후 과도하게 큰 감사 로그 항목

원본 로그 항목은 다음 항목으로 분할됩니다. 각 항목에는 4uidtotalSplits 값이 있는 split 객체가 포함됩니다. 각 항목에는 분할 로그 항목의 순서를 나타내는 split.index0, 1, 2, 3이 포함됩니다.

분할 로그 항목, 색인 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"},
      ]
    }
  }
}