콘텐츠로 건너뛰기
통합 가이드

node-postgres 풀 및 쿼리 Telemetry

SQL 매개변수를 기록하지 않고도 node-postgres 쿼리 지문, 연결 획득, 풀 압력, 시간 초과, 트랜잭션 결과 및 데이터베이스 오류를 계측합니다.

검토자 Telemetry 제품 팀 에 . 보낼 이벤트, 제외할 데이터, 코드 추가 방법을 확인했습니다. 이 페이지의 검토 담당자

다음에 유용합니다.
  • Postgres 연결 풀 모니터링
  • 느린 데이터베이스 운영 분석
  • 트랜잭션 및 시간 초과 디버깅
구현 증거

node-postgres pool and query telemetry로 이벤트 전송 및 확인

제어된 애플리케이션 경계에서 node-postgres pool and query telemetry를 사용하고, 이벤트 계약을 작게 유지하고, 집계 뷰를 구축하기 전에 알려진 결과를 확인하세요.

  1. 1

    결과를 선택하세요

    Postgres 연결 풀 모니터링

  2. 2

    계약 정의

    query_fingerprint, 서비스, database_name, 상태 및 duration_ms

  3. 3

    결과에서 방출

    원시 SQL에서 파생되는 대신 호출 사이트에서 제한된 지문을 전달합니다.

  4. 4

    증거를 확인하세요

    Exercise a known fixture, then inspect database_query_completed for one correctly typed terminal row.

시작하기 전에

시작하기 전에

  • 공유 풀이 포함된 pg 패키지
  • 애플리케이션 소유 작업 지문
  • 서버측 TELEMETRY_API_KEY
  • fetch와 AbortSignal.timeout을 지원하는 서버 런타임

배송 설정

서버 측 설치 및 초기화

이 서버 측 예제는 서버 측 키와 시간 제한이 있는 fetch 요청으로 Log API에 이벤트를 보냅니다. Telemetry SDK를 초기화할 필요가 없습니다. 브라우저 번들, 클라이언트에 표시되는 환경 변수, 소스 제어, 로그 및 예외 메시지에서 수집 자격 증명을 유지하세요.

node-postgres-설치

npm 설치

bash
npm install pg
  1. 1제한된 네트워크 동작을 갖춘 재사용 가능한 서버 측 전달 클라이언트 하나를 준비합니다.
  2. 2성공, 실패, 재시도 또는 시간 초과 경계에 결과 이벤트를 추가합니다.
  3. 3알림을 활성화하기 전에 제어된 고정 장치를 보내고 저장된 행을 검사하십시오.

스니펫

하나의 체계적인 이벤트로 시작하세요

워크플로가 완료, 실패 또는 재시도되는 위치에 이 셰이프를 추가합니다. 그런 다음 실제 필드에서 대시보드를 구축합니다.

node-postgres

node-postgres pool and query telemetry 이벤트

javascript
import { Pool } from "pg";

async function emitDatabaseOutcome(data) {
  try {
    const delivery = await fetch("https://api.telemetry.sh/log", {
      method: "POST",
      headers: {
        Authorization: process.env.TELEMETRY_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ table: "database_query_completed", data }),
      signal: AbortSignal.timeout(1000),
    });
    if (!delivery.ok) throw new Error("telemetry_delivery_unconfirmed");
  } catch {
    try { console.warn("Telemetry delivery unconfirmed"); } catch {}
  }
}

const pool = new Pool({ max: 10 });
const SAFE_DATABASE_ERROR_CODES = new Set(["40001", "40P01", "55P03", "57014"]);

function classifyDatabaseError(error) {
  return error && typeof error === "object" &&
    "code" in error &&
    SAFE_DATABASE_ERROR_CODES.has(String(error.code))
    ? String(error.code)
    : "database_error";
}

async function runDatabaseOperation({
  queryFingerprint,
  text,
  values,
}) {
  const acquireStartedAt = performance.now();
  let client;
  let acquisitionWaitMs;
  let queryStartedAt;
  let outcome;

  try {
    client = await pool.connect();
    acquisitionWaitMs = performance.now() - acquireStartedAt;
    queryStartedAt = performance.now();
    const result = await client.query(text, values);
    outcome = {
      query_fingerprint: queryFingerprint,
      service: "checkout-api",
      database_name: "app_production",
      status: "success",
      phase: "query",
      operation_duration_ms: Math.round(performance.now() - acquireStartedAt),
      duration_ms: Math.round(performance.now() - queryStartedAt),
      acquisition_wait_ms: Math.round(acquisitionWaitMs),
      rows_returned: result.rowCount ?? result.rows.length,
      active_connections: pool.totalCount - pool.idleCount,
      idle_connections: pool.idleCount,
      max_connections: pool.options.max ?? 10,
      waiting_count: pool.waitingCount,
      release: process.env.APP_RELEASE,
      environment: process.env.NODE_ENV,
    };
    return result;
  } catch (error) {
    outcome = {
      query_fingerprint: queryFingerprint,
      service: "checkout-api",
      database_name: "app_production",
      status: "failed",
      phase: queryStartedAt === undefined ? "acquire" : "query",
      duration_ms: queryStartedAt === undefined ? undefined : Math.round(performance.now() - queryStartedAt),
      acquisition_wait_ms: Math.round(acquisitionWaitMs ?? (performance.now() - acquireStartedAt)),
      operation_duration_ms: Math.round(performance.now() - acquireStartedAt),
      error_type: classifyDatabaseError(error),
      active_connections: pool.totalCount - pool.idleCount,
      idle_connections: pool.idleCount,
      max_connections: pool.options.max ?? 10,
      waiting_count: pool.waitingCount,
      release: process.env.APP_RELEASE,
      environment: process.env.NODE_ENV,
    };
    throw error;
  } finally {
    client?.release();
    if (outcome) await emitDatabaseOutcome(outcome);
  }
}

이벤트 스키마

query_fingerprint, 서비스, database_name, 상태 및 duration_ms

active_connections, idle_connections, max_connections 및 waiting_count

acquisition_wait_ms, operation_duration_ms, phase, rows_returned, error_type, release, and environment

설정 확인하기

체크포인트 1

원시 SQL에서 파생되는 대신 호출 사이트에서 제한된 지문을 전달합니다.

체크포인트 2

풀 경합이 데이터베이스 작업으로 오인되지 않도록 쿼리 실행과 별도로 연결 획득을 측정합니다.

체크포인트 3

허용 목록을 통해 드라이버 오류 코드를 기록하고 연결 문자열, 쿼리 매개변수 또는 원시 데이터베이스 메시지를 전달하지 마십시오.

체크포인트 4

결과를 보내기 전에 획득한 데이터베이스 클라이언트를 반환하세요. Log API의 1초 협력적 시간 제한과 보호된 진단 출력은 전송 실패가 데이터베이스 결과나 오류를 대체하지 않도록 합니다.

체크포인트 5

acquisition_wait_ms와 쿼리 실행 duration_ms를 별도로 기록하세요. 연결 획득 실패 시 쿼리 시간을 생략하며 operation_duration_ms는 두 단계를 포함합니다. 풀 수치는 클라이언트 반환 전에 기록합니다.

체크포인트 6

이 예제는 트랜잭션, 영속 전송, 재시도 또는 종료 시 전송 대기 처리를 구현하지 않습니다. 애플리케이션에서 데이터베이스 연결 및 쿼리 한도와 풀의 백그라운드 오류 처리를 설정하세요.

검증

이벤트가 도착했음을 증명하세요.

알려진 성공 및 실패 사례를 연습한 후 이를 실행하십시오. 최종 이벤트 계약이 스니펫과 다른 경우 대체 테이블 이름을 바꾸세요.

node-postgres-검증

node-postgres pool and query telemetry 확인 쿼리

sql
SELECT *
FROM database_query_completed
ORDER BY timestamp_utc DESC
LIMIT 20;
예상 상태, 식별자, 단위 및 UTC 시간을 사용하여 논리적 결과당 하나의 터미널 행을 확인합니다.
유추된 스키마를 검사하고 재시도가 필드 유형을 변경하거나 새 논리적 이벤트 ID를 생성하지 않는지 확인합니다.
자격 증명, 원시 페이로드, 프롬프트, 비공개 콘텐츠 및 무제한 오류 메시지에 대해 저장된 필드를 검색합니다.
대시보드를 완전한 것으로 처리하기 전에 공급자 시간 초과, 수집 거부 및 프로세스 종료를 실행합니다.

구현 참조

새로운 프로덕션 경로를 활성화하기 전에 이벤트 계약, 데이터 안전 지침, 업스트림 기본 문서를 검토하세요.

이벤트를 기록할 위치

결과 이벤트를 작고 복구 가능하게 유지

이 패턴은 다음을 제공합니다.

  • 업스트림 워크플로우 옆에 제한된 SQL 지원 결과가 있습니다.
  • 대시보드, 알림 및 교차 이벤트 상관 관계를 위한 안정적인 필드입니다.
  • 성공, 실패, 재시도 및 시간 초과 동작을 검증하기 위한 고정 장치 기반 경로입니다.

이 패턴은 제공하지 않습니다

  • OTLP 내보내기, 자동 수집 파이프라인 또는 자세한 추적 및 진단 로그를 대체합니다.
  • 페이로드에 이벤트 ID가 포함되어 있기 때문에 정확히 한 번만 전달됩니다.
  • 원시 공급자 페이로드, 사용자 콘텐츠, 자격 증명 또는 규제 데이터를 수집할 수 있는 권한입니다.

이벤트 스키마 예제

쿼리 또는 스니펫을 프로덕션에 적용하기 전에 행 그레인, 방출 경계, 필수 유형, 개인 정보 보호 클래스, 예제 페이로드 및 유효성 검사 체크리스트를 검토하세요.

관련 제품 기능

이 워크플로를 다음에서 계속하세요. SQL 쿼리 API

구조화된 이벤트 테이블에 대해 읽기 전용 DataFusion SQL을 실행하고 결과를 재사용합니다.

관련 SQL 레시피

더 많은 SQL 예제

이 워크플로의 구조화된 필드에 대해 쿼리를 실행하고, 예제 결과를 검사하고, 유용한 답변을 대시보드 또는 알림으로 전환하세요.

모든 레시피 찾아보기
데이터베이스 신뢰성초보자

지문으로 느린 데이터베이스 쿼리 찾기

조사할 만큼 지속적으로 느린 데이터베이스 작업은 무엇입니까?

레시피 열기
데이터베이스 신뢰성초보자

총 시간 영향을 기준으로 데이터베이스 쿼리 순위 지정

가장 많은 누적 요청 시간을 소모하는 데이터베이스 작업은 무엇입니까?

레시피 열기
데이터베이스 신뢰성초보자

데이터베이스 연결 풀 포화도 측정

호출자가 데이터베이스 연결을 기다리게 만드는 응용 프로그램 풀은 무엇입니까?

레시피 열기
데이터베이스 신뢰성중급

데이터베이스 연결 시간 초과 및 이탈 측정

비정상 데이터베이스 연결 변동이 나타나는 서비스와 지역은 무엇인가요?

레시피 열기
데이터베이스 신뢰성중급

데이터베이스 트랜잭션 롤백 비율 계산

데이터베이스 트랜잭션의 비정상적인 부분을 롤백하는 서비스는 무엇입니까?

레시피 열기
데이터베이스 신뢰성중급

장기 실행 데이터베이스 트랜잭션 측정

가장 오랫동안 열려 있는 애플리케이션 트랜잭션 클래스는 무엇입니까?

레시피 열기
데이터베이스 신뢰성중급

데이터베이스 잠금 대기 및 교착 상태 찾기

가장 심각한 잠금 경합을 일으키는 데이터베이스 작업은 무엇입니까?

레시피 열기
데이터베이스 신뢰성초보자

SQLSTATE 및 릴리스별 데이터베이스 오류 분석

애플리케이션 출시 이후 어떤 데이터베이스 오류 클래스가 증가했습니까?

레시피 열기
데이터베이스 신뢰성초보자

데이터베이스 복제 및 CDC 지연 측정

어떤 복제본이나 CDC 소비자가 소스 데이터베이스에 뒤처지고 있습니까?

레시피 열기
데이터베이스 신뢰성고급

지역별 데이터베이스 복제본 부실 상태 측정

오래되었거나 실패한 읽기를 제공하는 복제본 지역은 무엇입니까?

레시피 열기
데이터베이스 신뢰성초보자

릴리스별 데이터베이스 마이그레이션 실패 추적

어떤 릴리스에 실패했거나 롤백된 데이터베이스 마이그레이션이 포함되어 있습니까?

레시피 열기

구현 제품군별로 찾아보기

관련 통합 패턴 비교

이 통합과 페어링할 템플릿

더 많은 통합