샘플 SQL 쿼리

이 문서에는 로그 및 추적 데이터를 쿼리하는 데 사용할 수 있는 샘플 쿼리가 포함되어 있습니다.

SQL 언어 지원

로그 애널리틱스 페이지에서 사용되는 쿼리는 몇 가지 예외를 제외하고 GoogleSQL 함수를 지원합니다.

로그 애널리틱스 페이지를 사용하여 실행된 SQL 쿼리에는 다음 SQL 명령어가 지원되지 않습니다.

  • DDL 및 DML 명령어
  • JavaScript 사용자 정의 함수
  • BigQuery ML 함수
  • SQL 변수

다음은 BigQuery StudioLooker Studio 페이지를 사용하거나 bq 명령줄 도구를 사용하여 연결된 데이터 세트를 쿼리할 때만 지원됩니다.

  • JavaScript 사용자 정의 함수
  • BigQuery ML 함수
  • SQL 변수

권장사항

쿼리의 기간을 설정하려면 기간 선택기를 사용하는 것이 좋습니다. 예를 들어 지난주의 데이터를 보려면 기간 선택기에서 지난 7일을 선택합니다. 또한 기간 선택기를 사용하여 시작 및 종료 시간을 지정하고, 둘러볼 시간을 지정하고, 시간대를 변경할 수 있습니다.

로그 데이터

WHERE 절에 timestamp 필드를 포함하면 시간 범위 선택기 설정은 사용되지 않습니다. 다음 예는 타임스탬프로 필터링하는 방법을 보여줍니다.

-- Matches log entries whose timestamp is within the most recent 1 hour.
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

Trace 데이터

WHERE 절에 start_time 필드를 포함하면 시간 범위 선택기 설정은 사용되지 않습니다. 다음 예는 타임스탬프로 필터링하는 방법을 보여줍니다.

-- Matches trace spans whose start_time is within the most recent 1 hour.
WHERE start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

시간별로 필터링하는 방법에 대한 자세한 내용은 시간 함수타임스탬프 함수를 참고하세요.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. 관측 가능성 API를 사용 설정합니다.

    API 사용 설정에 필요한 역할

    API를 사용 설정하려면 serviceusage.services.enable 권한이 포함된 서비스 사용량 관리자 IAM 역할 (roles/serviceusage.serviceUsageAdmin)이 필요합니다. 역할 부여 방법 알아보기

    API 사용 설정하기

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. 관측 가능성 API를 사용 설정합니다.

    API 사용 설정에 필요한 역할

    API를 사용 설정하려면 serviceusage.services.enable 권한이 포함된 서비스 사용량 관리자 IAM 역할 (roles/serviceusage.serviceUsageAdmin)이 필요합니다. 역할 부여 방법 알아보기

    API 사용 설정하기

  8. 로그 애널리틱스 페이지를 로드하고, 추적 데이터에 대한 비공개 쿼리를 작성, 실행, 저장하는 데 필요한 권한을 얻으려면 관리자에게 다음 IAM 역할을 부여해 달라고 요청하세요.

    • 관측 가능성 뷰 접근자 (roles/observability.viewAccessor)를 부여해야 합니다. 쿼리할 관측 가능성 뷰에 대한 이 역할은 특정 뷰에 대한 권한 부여를 제한할 수 있는 IAM 조건을 지원합니다. 역할 부여에 조건을 연결하지 않으면 주 구성원이 모든 관측 가능성 뷰에 액세스할 수 있습니다. 관측 가능성 뷰는 공개 프리뷰 버전입니다.
    • 프로젝트의 관측 가능성 분석 사용자 (roles/observability.analyticsUser) 이 역할에는 비공개 쿼리를 저장하고 실행하고 공유 쿼리를 실행하는 데 필요한 권한이 포함되어 있습니다.
    • 프로젝트의 로그 뷰어 (roles/logging.viewer)
    • 쿼리하려는 로그 뷰를 저장하는 프로젝트에 대한 로그 뷰 접근자 (roles/logging.viewAccessor).

    역할 부여에 대한 자세한 내용은 프로젝트, 폴더, 조직에 대한 액세스 관리를 참조하세요.

    커스텀 역할이나 다른 사전 정의된 역할을 통해 필요한 권한을 얻을 수도 있습니다.

이 페이지의 쿼리를 사용하는 방법

  1. Google Cloud 콘솔에서 로그 애널리틱스 페이지로 이동합니다.

    로그 애널리틱스로 이동

    검색창을 사용하여 이 페이지를 찾은 경우 부제목이 Logging인 결과를 선택합니다.

  2. 쿼리 창에서  SQL을 클릭한 다음 쿼리를 복사하여 SQL 쿼리 창에 붙여넣습니다.

    로그 데이터

    쿼리를 복사하기 전에 FROM 절에서 다음 필드를 바꿉니다.

    • PROJECT_ID: 프로젝트 식별자
    • LOCATION: 로그 뷰 또는 분석 뷰의 위치
    • BUCKET_ID: 로그 버킷의 이름 또는 ID
    • LOG_VIEW_ID: 로그 뷰의 식별자. 100자(영문 기준)로 제한되며 문자, 숫자, 밑줄, 하이픈만 포함할 수 있습니다.

    다음은 로그 뷰FROM 절 형식을 보여줍니다.

    FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
    

    이 페이지의 로그 샘플은 로그 뷰를 쿼리합니다. 애널리틱스 뷰를 쿼리하려면 다음 경로 형식을 사용합니다. `analytics_view.PROJECT_ID.LOCATION.ANALYTICS_VIEW_ID` 앞의 표현식에서 PROJECT_ID는 프로젝트 ID이고 LOCATIONANALYTICS_VIEW_ID는 분석 보기의 위치와 이름입니다.

    Trace 데이터

    다음은 _AllSpans 보기를 쿼리하기 위한 FROM 원인의 형식을 보여줍니다.

    FROM `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
    

    FROM 절에는 다음 필드가 포함됩니다.

    • PROJECT_ID: 프로젝트 식별자
    • LOCATION: 관측 가능성 버킷의 위치입니다.
    • _Trace은 관측 가능성 버킷의 이름입니다.
    • Spans는 데이터 세트 이름입니다.
    • _AllSpans는 뷰 이름입니다.

BigQuery Studio 페이지에서 이 문서에 표시된 쿼리를 사용하거나 bq 명령줄 도구를 사용하려면 FROM 절을 수정하고 연결된 데이터 세트의 경로를 입력하세요.

로그 데이터

예를 들어 myproject 프로젝트에 있는 연결된 데이터 세트 mydataset_AllLogs 뷰를 쿼리하려면 경로는 myproject.mydataset._AllLogs입니다.

Trace 데이터

예를 들어 myproject 프로젝트에 있는 연결된 데이터 세트 my_linked_dataset_AllSpans 뷰를 쿼리하려면 경로는 `myproject.my_linked_dataset._AllSpans`입니다.

일반적인 사용 사례

이 섹션에는 맞춤 쿼리를 만드는 데 도움이 될 수 있는 몇 가지 일반적인 사용 사례가 나열되어 있습니다.

기본 로그 버킷에 로그 항목 표시

_Default 버킷을 쿼리하려면 다음 쿼리를 실행합니다.

SELECT
  timestamp, severity, resource.type, log_name, text_payload, proto_payload, json_payload
FROM
  `PROJECT_ID.LOCATION._Default._AllLogs`
-- Limit to 1000 entries
LIMIT 1000

정규 표현식으로 필드 값 추출

정규 표현식을 사용하여 문자열에서 값을 추출하려면 REGEXP_EXTRACT 함수를 사용합니다.

SELECT
  -- Display the timestamp, and the part of the name that begins with test.
  timestamp, REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Get the value of jobName, which is a subfield in a JSON structure.
  JSON_VALUE(json_payload.jobName) IS NOT NULL
ORDER BY timestamp DESC
LIMIT 20

자세한 내용은 REGEXP_EXTRACT 문서를 참고하세요.

이전 쿼리와 같은 하위 문자열 일치의 경우 CONTAINS_SUBSTR 함수를 사용하면 쿼리가 더 효율적입니다.

모든 trace 데이터 표시

_AllSpans 뷰를 쿼리하려면 다음 쿼리를 실행합니다.

-- Display all data.
SELECT *
FROM `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
-- Limit to 10 entries.
LIMIT 10

일반적인 스팬 정보 표시

시작 시간, 기간과 같은 일반적인 스팬 정보를 표시하려면 다음 쿼리를 실행하세요.

SELECT
  start_time,
  -- Set the value of service name based on the first non-null value in the list.
  COALESCE(
    JSON_VALUE(resource.attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."g.co/gae/app/module"')) AS service_name,
  name AS span_name,
  duration_nano,
  status.code AS status,
  trace_id,
  span_id
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
LIMIT 10

자세한 내용은 조건식을 참고하세요.

스팬 지연 시간의 50번째 및 99번째 백분위수 표시

각 RPC 서비스의 지연 시간의 50번째 및 99번째 백분위수를 표시하려면 다음 쿼리를 실행합니다.

SELECT
  -- Compute 50th and 99th percentiles for each service
  STRING(attributes['rpc.service']) || '/' || STRING(attributes['rpc.method']) AS rpc_service_method,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(50)] AS duration_nano_p50,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(99)] AS duration_nano_p99
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE
  -- Matches spans whose kind field has a value of 2 (SPAN_KIND_SERVER).
  kind = 2
GROUP BY rpc_service_method

열거형에 대한 자세한 내용은 OpenTelemetry: SpanKind 문서를 참고하세요.

결과를 그래픽으로 보려면 측정기준이 rpc_service_method로 설정된 차트를 만들면 됩니다. duration_nano_p50 값의 평균을 나타내는 측정항목과 duration_nano_p99 필드의 평균을 나타내는 측정항목을 추가할 수 있습니다.

로그 항목 필터링

쿼리에 필터를 적용하려면 WHERE 절을 추가합니다. 이 절에서 사용하는 구문은 필드의 데이터 유형에 따라 다릅니다. 이 섹션에서는 다양한 데이터 유형의 여러 예를 제공합니다.

페이로드 유형별 로그 항목 필터링

로그 항목에는 세 가지 페이로드 유형 중 하나가 있을 수 있습니다. 페이로드 유형별로 로그 항목을 필터링하려면 다음 절 중 하나를 사용하세요.

  • 텍스트 페이로드

    -- Matches log entries that have a text payload.
    WHERE text_payload IS NOT NULL
    
  • JSON 페이로드

    -- Matches log entries that have a JSON payload.
    WHERE json_payload IS NOT NULL
    
  • Proto 페이로드

    -- Matches log entries that have a proto payload.
    -- Because proto_payload has a data type of RECORD, this statement tests
    -- whether a mandatory subfield exits.
    WHERE proto_payload.type IS NOT NULL
    

쿼리 결과에서 json_payloadproto_payload 필드가 모두 JSON으로 렌더링되며, 이를 통해 탐색할 수 있습니다.

타임스탬프로 로그 데이터 필터링

타임스탬프로 로그 항목을 필터링하려면 기간 선택기를 사용하는 것이 좋습니다. 하지만 WHERE 절에서 timestamp를 지정할 수도 있습니다.

-- Matches log entries whose timestamp is within the most recent hour
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

시간별로 필터링하는 방법에 대한 자세한 내용은 시간 함수타임스탬프 함수를 참조하세요.

리소스별 필터링

리소스별로 로그 및 추적 데이터를 필터링하려면 WHERE 절에 resource.type 문을 추가합니다.

-- Matches log entries whose resource type is gce_instance
WHERE resource.type = "gce_instance"

심각도별 필터링

심각도별로 로그 데이터를 필터링하려면 WHERE 절에 severity 문을 추가합니다.

-- Matches log entries whose severity is INFO or ERROR
WHERE severity IS NOT NULL AND severity IN ('INFO', 'ERROR')

정수인 severity_number로 로그 항목을 필터링할 수도 있습니다. 예를 들어 다음 절은 심각도 수준이 최소 NOTICE인 모든 로그 항목과 일치합니다.

-- Matches log entries whose severity level is at least NOTICE
WHERE severity_number IS NOT NULL AND severity_number > 200

열거된 값에 대한 자세한 내용은 LogSeverity를 참조하세요.

로그 이름으로 필터링

로그 이름으로 로그 데이터를 필터링하려면 WHERE 절에 log_name 또는 log_id 문을 추가합니다.

  • 로그 이름은 리소스 경로를 지정합니다.

    -- Matches log entries that have the following log ID.
    WHERE log_name="projects/cloud-logs-test-project/logs/cloudaudit.googleapis.com%2Factivity"
    
  • 로그 ID는 리소스 경로를 생략합니다.

    -- Matches log entries that have the following log id.
    WHERE log_id = "cloudaudit.googleapis.com/data_access"
    

리소스 라벨별 로그 항목 필터링

리소스 라벨은 JSON 구조로 저장됩니다. JSON 구조 내 필드 값으로 필터링하려면 JSON_VALUE 함수를 사용합니다.

SELECT
  timestamp, JSON_VALUE(resource.labels.zone) AS zone, json_payload, resource, labels
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Matches log entries whose resource type is gce_instance and whose zone is
  -- us-central1-f. Because resource has data type JSON, you must use JSON_VALUE
  -- to get the value for subfields, like zone.
  resource.type = "gce_instance" AND
  JSON_VALUE(resource.labels.zone) = "us-central1-f"
ORDER BY timestamp ASC

이전 쿼리는 로그 항목에 저장된 리소스 라벨 형식을 사용합니다. 다음은 리소스 필드의 예입니다.

{
   type: "gce_instance"
   labels: {
      instance_id: "1234512345123451"
      project_id: "my-project"
      zone: "us-central1-f"
   }
}

JSON 데이터를 검색하고 변환할 수 있는 모든 함수에 대한 자세한 내용은 JSON 함수를 참조하세요.

HTTP 요청으로 필터링

HTTP 요청 필드가 있는 로그 항목만 쿼리하려면 다음 절을 사용하세요.

-- Matches log entries that have a HTTP request_method field.
-- Don't compare http_request to NULL. This field has a data type of RECORD.
WHERE http_request.request_method IS NOT NULL

IN 문을 사용할 수도 있습니다.

-- Matches log entries whose HTTP request_method is GET or POST.
WHERE http_request.request_method IN ('GET', 'POST')

HTTP 상태로 필터링

HTTP 상태가 있는 로그 항목만 쿼리하려면 다음 절을 사용하세요.

-- Matches log entries that have an http_request.status field.
WHERE http_request.status IS NOT NULL

JSON 데이터 유형 내의 필드로 필터링

JSON 데이터 유형이 있는 필드의 하위 필드에 특정 값이 있는 경우에만 로그 항목을 쿼리하려면 JSON_VALUE 함수를 사용하여 값을 추출합니다.

-- Compare the value of the status field to NULL.
WHERE JSON_VALUE(json_payload.status) IS NOT NULL

이전 절은 다음 절과 미묘하게 다릅니다.

-- Compare the status field to NULL.
WHERE json_payload.status IS NOT NULL

첫 번째 절에서는 상태 필드의 값이 NULL인지 테스트합니다. 두 번째 절에서는 상태 필드가 있는지 테스트합니다. 로그 뷰에 로그 항목이 두 개 포함되어 있다고 가정해 보겠습니다. 한 로그 항목의 경우 json_payload 필드의 형식은 다음과 같습니다.

{
    status: {
        measureTime: "1661517845"
    }
}

다른 로그 항목의 경우 json_payload 필드의 구조가 다릅니다.

{
    @type: "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished"
    jobName: "projects/my-project/locations/us-central1/jobs/test1"
    relativeUrl: "/food=cake"
    status: "NOT_FOUND"
    targetType: "APP_ENGINE_HTTP"
}

WHERE json_payload.status IS NOT NULL 절은 두 로그 항목과 모두 일치합니다. 하지만 WHERE JSON_VALUE(json_payload.status) IS NOT NULL 절은 두 번째 로그 항목만 일치합니다.

트레이스 항목 필터링

쿼리에 필터를 적용하려면 WHERE 절을 추가합니다. 이 절에서 사용하는 구문은 필드의 데이터 유형에 따라 다릅니다. 이 섹션에서는 다양한 데이터 유형의 여러 예를 제공합니다.

문자열 데이터 유형별로 필터링

name 필드는 String로 저장됩니다.

  • name이 지정된 스팬만 분석하려면 다음 절을 사용하세요.

    -- Matches spans that have a name field.
    WHERE name IS NOT NULL
    
  • name의 값이 "POST"인 스팬만 분석하려면 다음 절을 사용하세요.

    -- Matches spans whose name is POST.
    WHERE STRPOS(name, "POST") > 0
    
  • name"POST" 값이 포함된 스팬만 분석하려면 와일드 카드와 함께 LIKE 연산자를 사용합니다.

    -- Matches spans whose name contains POST.
    WHERE name LIKE "%POST%"
    

정수 데이터 유형별로 필터링

kind 필드는 0~5 사이의 값을 사용할 수 있는 정수입니다.

  • kind이 지정된 스팬만 분석하려면 다음 절을 사용하세요.

    -- Matches spans that have field named kind.
    WHERE kind IS NOT NULL
    
  • kind 값이 1 또는 2인 스팬을 분석하려면 다음 절을 사용하세요.

    -- Matches spans whose kind value is 1 or 2.
    WHERE kind IN (1, 2)
    

RECORD 데이터 유형별로 필터링

트레이스 스키마의 일부 필드는 데이터 유형이 RECORD입니다. 이러한 필드는 하나 이상의 데이터 구조를 저장하거나 동일한 데이터 구조의 반복 항목을 저장할 수 있습니다.

상태 또는 상태 코드로 필터링

status 필드는 데이터 유형이 RECORD인 필드의 예입니다. 이 필드는 codemessage로 라벨이 지정된 멤버가 있는 하나의 데이터 구조를 저장합니다.

  • status.code 필드의 값이 1인 경우에만 스팬을 분석하려면 다음 절을 추가합니다.

    -- Matches spans that have a status.code field that has a value of 1.
    WHERE status.code = 1
    

    status.code 필드는 정수로 저장됩니다.

  • status 필드가 EMPTY이 아닌 스팬을 분석하려면 다음 절을 추가하세요.

    -- Matches spans that have status field. When the status field exists, it
    -- must contain a subfield named code.
    -- Don't compare status to NULL, because this field has a data type of RECORD.
    WHERE status.code IS NOT NULL
    

eventslinks 필드는 데이터 유형이 RECORD인 필드로 저장되지만 반복 필드입니다.

  • 이벤트가 하나 이상 있는 스팬을 일치시키려면 다음 절을 사용하세요.

    -- Matches spans that have at least one event. Don't compare events to NULL.
    -- The events field has data type of RECORD and contains a repeated fields.
    WHERE ARRAY_LENGTH(events) > 0
    
  • name 필드 값이 message인 이벤트가 있는 스팬과 일치시키려면 다음 절을 사용하세요.

    WHERE
      -- Exists is true when any event in the array has a name field with the
      -- value of message.
      EXISTS(
        SELECT 1
        FROM UNNEST(events) AS ev
        WHERE ev.name = 'message'
      )
    

JSON 데이터 유형으로 필터링

attributes 필드는 JSON 유형입니다. 각 개별 속성은 키-값 쌍입니다.

  • attributes이 지정된 스팬만 분석하려면 다음 절을 사용하세요.

    -- Matches spans where at least one attribute is specified.
    WHERE attributes IS NOT NULL
    
  • component이라는 속성 키의 값이 "proxy"인 스팬만 분석하려면 다음 절을 사용합니다.

    -- Matches spans that have an attribute named component with a value of proxy.
    WHERE attributes IS NOT NULL
          AND JSON_VALUE(attributes, '$.component') = 'proxy'
    

    와일드 카드와 함께 LIKE 문을 사용하여 포함 테스트를 실행할 수도 있습니다.

    -- Matches spans that have an attribute named component whose value contains proxy.
    WHERE attributes IS NOT NULL
          AND JSON_VALUE(attributes, '$.component') LIKE '%proxy%'
    

로그 항목 그룹화 및 집계

이 섹션에서는 이전 샘플을 기반으로 로그 항목을 그룹화하고 집계하는 방법을 보여줍니다. 그룹화를 지정하지 않고 집계를 지정하면 SQL에서 WHERE 절을 충족하는 모든 행을 하나의 그룹으로 처리하므로 하나의 결과가 출력됩니다.

모든 SELECT 표현식은 그룹 필드에 포함되거나 집계되어야 합니다.

타임스탬프별로 로그 항목 그룹화

타임스탬프별로 데이터를 그룹화하려면 타임스탬프를 HOUR과 같이 지정된 단위로 자르는 TIMESTAMP_TRUNC 함수를 사용합니다.

SELECT
  -- Truncate the timestamp by hour.
  TIMESTAMP_TRUNC(timestamp, HOUR) AS hour,
  JSON_VALUE(json_payload.status) AS status,
  -- Count the number log entries in each group.
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Matches log entries that have a status field whose value isn't NULL.
  json_payload IS NOT NULL AND JSON_VALUE(json_payload.status) IS NOT NULL
GROUP BY
  -- Group by hour and status
  hour,status
ORDER BY hour ASC

자세한 내용은 TIMESTAMP_TRUNC 문서날짜 시간 함수를 참고하세요.

리소스별로 로그 항목 그룹화

다음 쿼리는 리소스 유형별로 로그 항목을 그룹화한 다음 각 그룹의 로그 항목 수를 계산하는 방법을 보여줍니다.

SELECT
   -- Count the number of log entries for each resource type
   resource.type, COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
GROUP BY resource.type
LIMIT 100

심각도별로 로그 항목 그룹화

다음 쿼리는 심각도별로 로그 항목을 그룹화한 다음 각 그룹의 로그 항목 수를 계산하는 방법을 보여줍니다.

SELECT
  -- Count the number of log entries for each severity.
  severity, COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  severity IS NOT NULL
GROUP BY severity
ORDER BY severity
LIMIT 100

log_id별로 로그 항목 그룹화

다음 쿼리는 로그 ID별로 로그 항목을 그룹화한 다음 각 그룹의 로그 항목 수를 계산하는 방법을 보여줍니다.

SELECT
  -- Count the number of log entries for each log ID.
  log_id, COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
GROUP BY log_id
ORDER BY count DESC
LIMIT 100

URL별 HTTP 요청의 평균 지연 시간 계산

다음 쿼리는 HTTP 요청 URL과 위치별로 로그 항목을 그룹화한 다음 각 그룹의 로그 항목 수를 계산하는 방법을 보여줍니다.

SELECT
  -- Compute the average latency for each group. Because the labels field has a
  -- data type of JSON, use JSON_VALUE to get the value of checker_location.
  JSON_VALUE(labels.checker_location) AS location,
  AVG(http_request.latency.seconds) AS secs, http_request.request_url
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  -- Matches log entries when the request_method field is GET.
  http_request IS NOT NULL AND http_request.request_method IN ('GET')
GROUP BY
  -- Group by request URL and location
  http_request.request_url, location
ORDER BY location
LIMIT 100

서브네트워크 테스트를 위해 전송된 평균 바이트 계산

다음 쿼리는 리소스 라벨에 지정된 위치별로 로그 항목을 그룹화한 다음 각 그룹의 로그 항목 수를 계산하는 방법을 보여줍니다.

SELECT
  -- Compute the average number of bytes sent per location. Because labels has
  -- a data type of JSON, use JSON_VALUE to get the value of the location field.
  -- bytes_sent is a string. Must cast to a FLOAT64 before computing average.
  JSON_VALUE(resource.labels.location) AS location,
  AVG(CAST(JSON_VALUE(json_payload.bytes_sent) AS FLOAT64)) AS bytes
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  resource.type = "gce_subnetwork" AND json_payload IS NOT NULL
GROUP BY
  -- Group by location
  location
LIMIT 100

자세한 내용은 JSON 함수변환 함수를 참고하세요.

패턴과 일치하는 필드로 로그 항목 수 계산

정규 표현식과 일치하는 하위 문자열을 반환하려면 REGEXP_EXTRACT 함수를 사용합니다.

SELECT
  -- Extract the value that begins with test.
  -- Count the number of log entries for each name.
  REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
  json_payload.jobName IS NOT NULL
GROUP BY name
ORDER BY count
LIMIT 20

추가 예시는 REGEXP_EXTRACT 문서를 참조하세요.

추적 데이터 그룹화 및 집계

이 섹션에서는 스팬을 그룹화하고 집계하는 방법을 보여줍니다. 그룹화를 지정하지 않고 집계를 지정하면 SQL에서 WHERE 절을 충족하는 모든 항목을 하나의 그룹으로 취급하므로 결과가 하나 출력됩니다.

모든 SELECT 표현식은 그룹 필드에 포함되거나 집계되어야 합니다.

시작 시간별로 스팬 그룹화

시작 시간별로 데이터를 그룹화하려면 타임스탬프를 HOUR과 같이 지정된 단위로 자르는 TIMESTAMP_TRUNC 함수를 사용합니다.

SELECT
  -- Truncate the start time to the hour. Count the number of spans per group.
  TIMESTAMP_TRUNC(start_time, HOUR) AS hour,
  status.code AS code,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE
  -- Matches spans shows start time is within the previous 12 hours.
  start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 12 HOUR)
GROUP BY
  -- Group by hour and status code.
  hour, code
ORDER BY hour DESC

자세한 내용은 TIMESTAMP_TRUNC 문서날짜 시간 함수를 참고하세요.

상태 코드별 스팬 수

특정 상태 코드가 있는 스팬의 개수를 표시하려면 다음 쿼리를 실행합니다.

SELECT
  -- Count the number of spans for each status code.
  status.code,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE status.code IS NOT NULL
GROUP BY status.code

status.codekind로 바꾸면 이전 쿼리에서 kind 열거형의 각 값에 대한 범위 수를 보고합니다. 마찬가지로 status.codename로 바꾸면 쿼리 결과에 각 스팬 이름의 항목 수가 나열됩니다.

모든 스팬의 평균 지속 시간 계산

스팬 이름을 기준으로 스팬 데이터를 그룹화한 후 평균 기간을 표시하려면 다음 쿼리를 실행합니다.

SELECT
  -- Group by name, and then compute the average duration for each group.
  name,
  AVG(duration_nano) AS nanosecs,
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
GROUP BY name
ORDER BY nanosecs DESC

서비스 이름별 평균 기간 및 백분위수 계산

다음 쿼리는 각 서비스의 스팬 수와 다양한 통계를 계산합니다.

SELECT
  -- Set the service name by the first non-null value.
  COALESCE(
    JSON_VALUE(resource.attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."g.co/gae/app/module"')) AS service_name,

  -- Count the number spans for each service name. Also compute statistics.
  COUNT(*) AS span_count,
  AVG(duration_nano) AS avg_duration_nano,
  MIN(duration_nano) AS min_duration_nano,
  MAX(duration_nano) AS max_duration_nano,

  -- Calculate percentiles for duration
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(50)] AS p50_duration_nano,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(95)] AS p95_duration_nano,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(99)] AS p99_duration_nano,

  -- Count the number of unique trace IDs. Also, collect up to 5 unique
  -- span names and status codes.
  COUNT(DISTINCT trace_id) AS distinct_trace_count,
  ARRAY_AGG(DISTINCT name IGNORE NULLS LIMIT 5) AS sample_span_names,
  ARRAY_AGG(DISTINCT status.code IGNORE NULLS LIMIT 5) AS sample_status_codes
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
GROUP BY service_name
ORDER BY span_count DESC

이 섹션에서는 쿼리 중인 뷰의 여러 열을 검색하는 데 사용할 수 있는 두 가지 접근 방식을 설명합니다.

  • 토큰 기반 검색: 검색 위치와 검색어를 지정한 다음 SEARCH 함수를 사용합니다. SEARCH 함수에는 데이터 검색 방법에 관한 특정 규칙이 있으므로 SEARCH 문서를 읽어보시기 바랍니다.

  • 부분 문자열 기반 검색: 검색 위치와 문자열 리터럴을 제공한 다음 CONTAINS_SUBSTR 함수를 사용합니다. 시스템은 대소문자를 구분하지 않는 테스트를 실행하여 문자열 리터럴이 표현식에 있는지 확인합니다. CONTAINS_SUBSTR 함수는 문자열 리터럴이 있으면 TRUE를 반환하고 그렇지 않으면 FALSE를 반환합니다. 검색 값은 STRING 리터럴이어야 하지만 리터럴 NULL은 아니어야 합니다.

다음 쿼리는 '35.193.12.15'와 정확히 일치하는 필드가 있는 행만 보관합니다.

SELECT
  timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID` AS t
WHERE
  -- Search data access audit logs for the IP address that matches 35.193.12.15.
  -- The use of backticks prevents the string from being tokenized.
  proto_payload IS NOT NULL AND
  log_id = "cloudaudit.googleapis.com/data_access" AND
  SEARCH(t,"`35.193.12.15`")
ORDER BY timestamp ASC
LIMIT 20

쿼리 문자열에서 백틱이 생략되면 SEARCH 문서에 정의된 규칙에 따라 쿼리 문자열이 분할됩니다. 예를 들어 다음 문장을 실행하면 쿼리 문자열이 '35', '193', '12', '15'의 네 개 토큰으로 분할됩니다.

  SEARCH(t,"35.193.12.15")

이전 SEARCH 문은 단일 필드가 네 개의 토큰과 모두 일치할 때 행과 일치합니다. 토큰의 순서는 중요하지 않습니다.

쿼리에 여러 SEARCH 문을 포함할 수 있습니다. 예를 들어 이전 쿼리에서 로그 ID에 대한 필터를 다음과 같은 문으로 바꿀 수 있습니다.

  SEARCH(t,"`cloudaudit.googleapis.com/data_access`")

이전 문은 로그 뷰의 로그 항목에 있는 모든 필드를 검색하는 반면 원래 문은 로그 항목의 log_id 필드만 검색합니다.

여러 필드에 대해 다중 검색을 수행하려면 개별 문자열을 공백으로 구분합니다. 예를 들어 다음 문은 필드에 'Hello World', 'happy', 'days'가 포함된 행과 일치합니다.

  SEARCH(t,"`Hello World` happy days")

마지막으로 전체 표를 검색하는 대신 특정 필드를 검색할 수 있습니다. 예를 들어 다음 문은 text_payloadjson_payload이라는 이름의 열만 검색합니다.

   SEARCH((text_payload, json_payload) ,"`35.222.132.245`")

SEARCH 함수의 매개변수가 처리되는 방법에 대한 자세한 내용은 BigQuery 참조 페이지 검색 함수를 참조하세요.

예를 들어 다음 쿼리는 특정 기간에 타임스탬프가 있는 특정 IP 주소가 포함된 모든 데이터 액세스 감사 로그 항목을 가져옵니다. 마지막으로 쿼리는 결과를 정렬한 후 가장 오래된 결과 20개를 표시합니다.

SELECT
  timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID` AS t
WHERE
  -- Search data access audit logs for the IP address that matches 35.193.12.15.
  -- CONTAINS_SUBSTR performs a contains-test.
  proto_payload IS NOT NULL AND
  log_id = "cloudaudit.googleapis.com/data_access" AND
  CONTAINS_SUBSTR(t,"35.193.12.15")
ORDER BY timestamp ASC
LIMIT 20

여러 뷰 쿼리

쿼리 문은 테이블 또는 표현식을 한 개 이상 검색하고 계산된 결과 행을 반환합니다. 예를 들어 쿼리 문을 사용하여 다양한 방식으로 서로 다른 테이블 또는 데이터 세트에 대한 SELECT 문의 결과를 병합한 후 결합된 데이터에서 해당 열을 선택할 수 있습니다.

뷰를 결합하려면 다음 제한사항이 적용됩니다.

  1. 뷰의 위치가 다음 중 하나를 충족합니다.

    • 모든 뷰의 위치가 동일합니다.
    • 모든 조회수는 global 또는 us 위치에서 발생합니다.
  2. 스토리지 리소스가 고객 관리 암호화 키 (CMEK)를 사용하는 경우 다음 중 하나가 참입니다.

    • CMEK를 사용하는 스토리지 리소스는 동일한 Cloud KMS 키를 사용합니다.
    • CMEK를 사용하는 스토리지 리소스에는 공통 상위 항목이 있으며, 이 상위 항목은 스토리지 리소스와 동일한 위치에 있는 기본 Cloud KMS 키를 지정합니다.

    하나 이상의 스토리지 리소스가 CMEK를 사용하는 경우 시스템은 공통 Cloud KMS 키 또는 상위 항목의 기본 Cloud KMS 키를 사용하여 조인에서 생성된 임시 데이터를 암호화합니다.

예를 들어 동일한 위치에 있는 두 개의 뷰가 있다고 가정해 보겠습니다. 그런 다음 다음 중 하나라도 해당하는 경우 이러한 뷰를 조인할 수 있습니다.

  • 스토리지 리소스가 CMEK를 사용하지 않습니다.
  • 한 스토리지 리소스는 CMEK를 사용하고 다른 스토리지 리소스는 CMEK를 사용하지 않습니다.
  • 두 스토리지 리소스 모두 CMEK를 사용하고 동일한 Cloud KMS 키를 사용합니다.
  • 두 스토리지 리소스 모두 CMEK를 사용하지만 서로 다른 키를 사용합니다. 하지만 리소스는 스토리지 리소스와 동일한 위치에 있는 기본 Cloud KMS 키를 지정하는 상위 항목을 공유합니다.

    예를 들어 로그 버킷과 관측 가능성 버킷의 리소스 계층 구조에 동일한 조직이 포함된다고 가정해 보겠습니다. 해당 조직에 대해 스토리지 위치의 기본 Cloud KMS 키가 동일한 Cloud Logging의 기본 리소스 설정관측 가능성 버킷을 구성한 경우 이러한 버킷의 뷰를 조인할 수 있습니다.

trace ID로 두 로그 뷰 조인

두 테이블의 정보를 결합하려면 조인 연산자 중 하나를 사용합니다.

SELECT
  -- Do an inner join on two tables by using the span ID and trace ID.
  -- Don't join only by span ID, as this field isn't globally unique.
  -- From the first view, show the timestamp, severity, and JSON payload.
  -- From the second view, show the JSON payload.
  a.timestamp, a.severity, a.json_payload, b.json_payload, a.span_id, a.trace
FROM  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_1` a
JOIN  `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_2` b
ON
  a.span_id = b.span_id AND
  a.trace = b.trace
LIMIT 100

유니온 문을 사용하여 두 개의 로그 뷰 쿼리

두 개 이상의 SELECT 문의 결과를 결합하고 중복 행을 삭제하려면 UNION 연산자를 사용합니다. 중복 행을 유지하려면 UNION ALL 연산자를 사용합니다.

SELECT
  timestamp, log_name, severity, json_payload, resource, labels
-- Create a union of two log views
FROM(
  SELECT * FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_1`
  UNION ALL
  SELECT * FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_2`
)
-- Sort the union by timestamp.
ORDER BY timestamp ASC
LIMIT 100

추적 ID를 사용하여 추적 및 로그 데이터 조인

다음 쿼리는 스팬 및 트레이스 ID를 사용하여 로그 및 트레이스 데이터를 조인합니다.

SELECT
  T.trace_id,
  T.span_id,
  T.name,
  T.start_time,
  T.duration_nano,
  L.log_name,
  L.severity,
  L.json_payload
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans` AS T
JOIN
  `PROJECT_ID.LOCATION._Default._AllLogs` AS L
ON
  -- Join log and trace data by both the span ID and trace ID.
  -- Don't join only on span ID, this field isn't globally unique.
  T.span_id = L.span_id
  -- A regular expression is required because the storage format of the trace ID
  -- differs between a log view and a trace view.
  AND T.trace_id = REGEXP_EXTRACT(L.trace, r'/([^/]+)$')
WHERE T.duration_nano > 1000000
LIMIT 10

쿼리 응답에는 추적 및 스팬 ID가 나열되어 있으므로 이를 개별적으로 쿼리하여 자세한 정보를 수집할 수 있습니다. 또한 결과에는 로그 항목의 심각도와 JSON 페이로드가 나열됩니다.

중복 로그 항목 삭제

로그 애널리틱스는 쿼리가 실행되기 전에 중복 로그 항목을 삭제하지 않습니다. 이 동작은 로그 이름, 타임스탬프, 삽입 ID 필드를 비교하여 중복 항목을 삭제하는 로그 탐색기를 사용하여 로그 항목을 쿼리할 때와 다릅니다.

행 수준 유효성 검사를 사용하면 중복 로그 항목을 삭제할 수 있습니다.

자세한 내용은 문제 해결: 로그 애널리틱스 결과에 중복된 로그 항목이 있음을 참조하세요.

다음 단계

SQL 참고 문서 또는 기타 예시는 다음 문서를 참고하세요.