본문으로 건너뛰기

10.2 로깅

전통적인 PostgreSQL 운영에서는 로그가 서버 안 log/ 디렉토리에 파일로 쌓였다. Kubernetes에서는 방식이 다르다. CloudNativePG는 PostgreSQL 로그를 포함한 모든 로그를 JSON 형식으로 표준 출력(stdout)에만 흘려보내고, 파일로 저장하지 않는다. 보관과 검색은 컨테이너 로그를 수집하는 Kubernetes 계층(로그 수집기 + 저장소)이 담당한다. 즉 애플리케이션은 로그를 뿜기만 하고, 어디에 얼마나 오래 둘지는 인프라가 정하는 구조다.

    flowchart TD
  PG["postgres"]
  IM["instance-manager"]
  STDOUT["stdout<br/>(JSON 한 줄)"]
  COLL["로그 수집기<br/>(Fluent Bit 등)"]
  STORE[("로그 저장소<br/>Loki·ES")]
  PG --> IM
  IM -->|JSON 변환| STDOUT
  STDOUT -->|컨테이너 로그| COLL
  COLL --> STORE

  classDef node fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
  class PG,IM,STDOUT,COLL,STORE node
  

JSON 로그 구조

로그는 한 줄에 JSON 객체 하나다. 사람이 읽기엔 다소 빽빽하지만, 기계가 파싱하고 필드로 검색하기에는 훨씬 낫다. 모든 레코드는 공통 필드를 갖는다.

필드의미
level심각도 — error, warning, info, debug, trace
ts타임스탬프
logger로그를 낸 프로세스 종류
msg메시지. 구조화된 경우 "record"
recordlogger 종류에 따라 달라지는 실제 내용
logging_pod로그를 낸 Pod 이름

PostgreSQL 자체 로그도 이 틀 안에 들어간다. 이때 loggerpostgres이고, record 안에 PostgreSQL의 CSV 로그 필드가 그대로 담긴다.

{
  "level": "info",
  "ts": "2026-07-05T09:12:34.567Z",
  "logger": "postgres",
  "msg": "record",
  "record": {
    "log_time": "2026-07-05 09:12:34.567 UTC",
    "user_name": "app",
    "database_name": "app",
    "process_id": "1234",
    "error_severity": "LOG",
    "sql_state_code": "00000",
    "message": "connection authorized: user=app database=app"
  },
  "logging_pod": "cluster-example-1"
}

logger 종류

logger 필드를 보면 로그가 어느 단계에서 나왔는지 알 수 있다. 문제를 쫓을 때 이 값으로 먼저 걸러 내면 범위가 크게 좁혀진다.

logger출처
postgresPostgreSQL 인스턴스
instance-managerPod 안에서 postgres를 지키는 인스턴스 매니저
initdb클러스터 초기화
wal-archive / wal-restoreWAL 아카이브·복원
barman-cloud-wal-archive / barman-cloud-wal-restoreBarman 기반 WAL 작업
pg_basebackup, pg_ctl, pg_rewindPostgreSQL 유틸리티
pgauditPGAudit 감사 로그

로그 레벨

로그 레벨은 인스턴스와 Operator에서 따로 정한다.

클러스터의 .spec.logLevel로 지정한다. 값은 error·warning·info(기본)·debug·trace다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 3
  logLevel: info
로그 레벨은 인스턴스가 시작할 때만 적용된다. 이미 떠 있는 Pod의 레벨을 바꾸려면 해당 Pod가 새로 뜨는 시점(rolling update 등)을 거쳐야 한다.

pgaudit 감사 로그

CloudNativePG는 감사 로깅 확장인 PGAudit를 기본으로 통합한다. postgresql 설정에 pgaudit 파라미터를 주기만 하면, Operator가 shared_preload_libraries에 pgaudit를 넣고 빼는 일과 모든 데이터베이스에서 확장을 만들고 지우는 일을 알아서 처리한다.

spec:
  postgresql:
    parameters:
      pgaudit.log: "all, -misc"
      pgaudit.log_catalog: "off"

감사 레코드는 logger: "pgaudit"로 나오며, record.audit 안에 감사 메타데이터(audit_type, statement_id, class, command, statement, parameter)가 담긴다. 로그 수집기에서 logger == "pgaudit"로 필터링하면 감사 로그만 따로 모을 수 있다.

로그 수집

로그가 stdout으로 나오므로, 컨테이너 로그를 다루는 어떤 도구와도 자연스럽게 맞물린다. 가볍게 실시간으로 볼 때는 stern이 편하다.

# cluster-example로 시작하는 모든 Pod의 로그를 한 번에 tail
stern cluster-example

프로덕션에서는 Fluent Bit·Fluentd 같은 수집기를 노드마다 두어 컨테이너 로그를 긁고, Loki나 Elasticsearch에 적재해 검색·보관한다.

JSON 필드 이름이 기존 로그 파이프라인과 충돌하면, Operator의 log-field-level·log-field-timestamp 플래그로 level·ts 필드 이름을 바꿀 수 있다.

정리

  • 모든 로그는 파일이 아니라 stdout으로, JSON 한 줄씩 나온다
  • 공통 필드(level·ts·logger·msg·record)로 파싱·검색한다
  • logger 값으로 postgres·instance-manager·wal-archive 등 출처를 구분한다
  • 로그 레벨은 시작 시점에만 적용되고, 감사는 pgaudit로 통합된다
  • 보관·검색은 stern·Fluent Bit·Loki 같은 Kubernetes 계층 도구가 맡는다

다음 절(10.3)에서는 이 모든 리소스에 Operator가 붙이는 label과 annotation을 읽는다.