PostgreSQL 오류 디버깅: VERBOSITY와 backtrace_functions로 스택 트레이스 확인하기
작성자: Phil Eaton
작성일: 2025년 7월 31일
PostgreSQL이 크래시하면 gdb를 사용해 스택 트레이스를 확인할 수 있습니다. 그렇다면 PostgreSQL이 크래시하지 않는 일반적인 오류는 어떻게 디버깅할 수 있을까요?
이 글에서는 PostgreSQL 17을 디버그 심볼과 함께 빌드한 뒤, psql의 VERBOSITY 옵션으로 오류 발생 위치를 확인하고 backtrace_functions GUC를 사용해 서버 로그에 스택 트레이스를 출력하는 과정을 단계별로 살펴봅니다.
PostgreSQL 오류 디버깅 핵심 요약
VERBOSITY verbose로 오류가 발생한 함수와 소스 파일 위치를 확인합니다.- 확인한 함수명을
backtrace_functions에 지정합니다. pg_reload_conf()로 설정을 재로드한 뒤 오류를 다시 실행합니다.- PostgreSQL 서버 로그에서 오류의 전체 호출 경로를 확인합니다.
1. PostgreSQL 17 소스 코드 빌드
먼저 PostgreSQL 17 소스를 가져와 디버그 심볼을 포함해 빌드해 보겠습니다.
$ git clone https://github.com/postgres/postgres
$ cd postgres
$ git checkout REL_17_STABLE
$ ./configure --enable-debug --without-icu \
--prefix=$(pwd)/build \
--libdir=$(pwd)/build/lib
$ make -j16 && make install2. 데이터베이스 생성 및 시작
$ ./build/bin/initdb testdb
$ ./build/bin/pg_ctl -D $(pwd)/testdb -l logfile start3. psql로 PostgreSQL 접속
$ ./build/bin/psql postgres
psql (17.5)
Type "help" for help.
postgres=#4. 존재하지 않는 테이블을 조회해 오류 발생시키기
존재하지 않는 테이블을 조회해 오류를 발생시킵니다.
postgres=# SELECT * FROM nothere;
ERROR: relation "nothere" does not exist
LINE 1: SELECT * FROM nothere;
^
postgres=#이 오류 자체는 디버깅할 필요가 없는 단순한 ERROR이지만, 여기서는 과정을 설명하기 위해 사용하겠습니다.
5. 문자열 검색으로 PostgreSQL 오류 원인 찾기
예전에는 이런 오류 메시지가 나오면 메시지의 고정된 문자열 부분을 추출해 git grep으로 검색하곤 했습니다.
$ git grep '"relation' | grep 'does not exist"' | grep '.c:'
src/backend/catalog/aclchk.c: errmsg("relation with OID %u does not exist",
src/backend/catalog/aclchk.c: errmsg("relation with OID %u does not exist",
src/backend/catalog/aclchk.c: errmsg("relation with OID %u does not exist",
src/backend/catalog/namespace.c: errmsg("relation \"%s.%s\" does not exist",
src/backend/catalog/namespace.c: errmsg("relation \"%s\" does not exist",
src/backend/parser/parse_relation.c: errmsg("relation \"%s.%s\" does not exist",
src/backend/parser/parse_relation.c: errmsg("relation \"%s\" does not exist",
src/backend/parser/parse_relation.c: errmsg("relation \"%s\" does not exist",
src/backend/utils/adt/regproc.c: errmsg("relation \"%s\" does not exist",
src/pl/plpgsql/src/pl_comp.c: errmsg("relation \"%s\" does not exist", ident)));이렇게 문자열 처리와 grep을 잘 조합하면 원인을 찾을 수도 있지만, 찾지 못할 수도 있습니다.
6. psql VERBOSITY로 오류 발생 위치 확인
보다 직접적인 방법은 psql에서 VERBOSITY를 verbose로 설정하는 것입니다. 이렇게 하면 오류가 발생한 함수명과 파일 위치를 확인할 수 있으며, 이 정보만으로도 상당 부분 문제를 해결할 수 있습니다.
postgres=# \set VERBOSITY verbose
postgres=# SELECT * FROM nothere;
ERROR: 42P01: relation "nothere" does not exist
LINE 1: SELECT * FROM nothere;
^
LOCATION: parserOpenTable, parse_relation.c:14527. backtrace_functions GUC로 스택 트레이스 출력
최근 온콜(on-call) 중에 backtrace_functions라는 GUC를 알게 되었습니다. 이 기능을 사용하면 PostgreSQL이 오류 발생 시 스택 트레이스를 로그로 남길 수 있습니다. 정말 유용하죠!
단, 로그를 발생시키는 모든 함수에 대해 무차별적으로 스택 트레이스를 출력하면 로그가 스팸처럼 쌓일 수 있으므로, 원하는 함수만 지정해야 합니다.
앞서 VERBOSITY verbose 설정으로 오류가 발생한 정확한 함수(parserOpenTable)를 확인했으므로, 이를 backtrace_functions에 지정하고 PostgreSQL 설정을 재로드합니다.
postgres=# ALTER SYSTEM SET backtrace_functions='parserOpenTable';
ALTER SYSTEM
postgres=# SELECT pg_reload_conf();
pg_reload_conf
----------------
t
(1 row)8. 오류 재실행 후 PostgreSQL 로그 확인
postgres=# SELECT * FROM nothere;
ERROR: 42P01: relation "nothere" does not exist
LINE 1: SELECT * FROM nothere;
^
LOCATION: parserOpenTable, parse_relation.c:1452이제 로그 파일에서 해당 오류의 스택 트레이스를 확인할 수 있습니다.
2025-07-31 13:46:42.657 EDT [84985] ERROR: relation "nothere" does not exist at character 15
2025-07-31 13:46:42.657 EDT [84985] BACKTRACE:
2 postgres 0x000000010499a0d0 parserOpenTable.cold.1 + 156
3 postgres 0x00000001045d64cc parserOpenTable + 124
4 postgres 0x00000001045d666c addRangeTableEntry + 272
5 postgres 0x00000001045c2744 transformFromClauseItem + 256
6 postgres 0x00000001045c25a8 transformFromClause + 132
7 postgres 0x00000001045ad3fc transformSelectStmt + 128
8 postgres 0x00000001045ac858 transformStmt + 4316
9 postgres 0x00000001045ab344 parse_analyze_fixedparams + 192
10 postgres 0x00000001048003a8 exec_simple_query + 1024
11 postgres 0x00000001047fe2a8 PostgresMain + 3108
12 postgres 0x00000001047fa08c BackendInitialize + 0
13 postgres 0x000000010476f22c PgArchShmemSize + 0
14 postgres 0x0000000104773308 ServerLoop + 6772
15 postgres 0x0000000104770d38 PostmasterMain + 3436
16 postgres 0x00000001046a5844 main + 800
17 dyld 0x0000000196993154 start + 24769. PostgreSQL 오류 스택 트레이스 기능의 향후 개선 가능성
현재는 특정 함수를 지정해야만 스택 트레이스를 출력할 수 있지만, 모든 오류에 대해 자동으로 스택 트레이스를 출력하는 패치도 제안되어 있습니다. 이는 오류 발생 빈도가 낮고 디버깅이 번거로운 자동화 테스트 환경에서 특히 유용할 것입니다. 앞으로 이 기능이 PostgreSQL에 공식 반영되기를 기대합니다.
PostgreSQL 오류 디버깅 FAQ
PostgreSQL에서 크래시하지 않는 일반 오류는 어떻게 디버깅하나요?
psql의 VERBOSITY를 verbose로 설정하면 오류 코드와 함께 오류가 발생한 함수명 및 소스 파일 위치를 확인할 수 있습니다. 확인한 함수명을 backtrace_functions에 지정하면 해당 함수에서 발생한 오류의 스택 트레이스를 서버 로그에 기록할 수 있습니다.
psql의 VERBOSITY verbose 옵션은 어떤 정보를 보여주나요?
VERBOSITY를 verbose로 설정하면 SQLSTATE 오류 코드, 오류 메시지, 오류가 발생한 함수명, 소스 파일명과 줄 번호를 확인할 수 있습니다. 이 정보는 오류 발생 지점을 소스 코드에서 직접 찾는 데 도움이 됩니다.
PostgreSQL의 backtrace_functions는 무엇인가요?
backtrace_functions는 지정한 C 함수에서 오류가 발생할 때 서버 로그에 스택 트레이스를 출력하도록 설정하는 GUC입니다. 오류가 전달된 호출 경로를 확인할 수 있어 원인 분석에 유용합니다.
backtrace_functions에 모든 함수를 지정해도 되나요?
로그를 발생시키는 모든 함수를 대상으로 스택 트레이스를 출력하면 로그가 과도하게 쌓일 수 있습니다. VERBOSITY verbose로 확인한 오류 발생 함수처럼 조사하려는 함수만 지정하는 것이 좋습니다.
backtrace_functions 설정 후 PostgreSQL을 다시 시작해야 하나요?
본문의 예시에서는 ALTER SYSTEM으로 backtrace_functions를 설정한 뒤 pg_reload_conf()를 실행해 설정을 다시 불러옵니다. 이후 같은 오류를 실행하면 서버 로그에서 해당 스택 트레이스를 확인할 수 있습니다.