首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >PG实时堆栈跟踪

PG实时堆栈跟踪

作者头像
用户4035096
发布2026-07-09 18:50:49
发布2026-07-09 18:50:49
20
举报

使用开发者参数 backtrace_functions 对 Postgres 错误进行实时堆栈跟踪

当你在PostgreSQL中执行SQL出错时, 如何能跟踪导致出错的堆栈?

你可能会想到gdb, 是的, 比如等等数据库崩溃, 打印core dump, 从core dump文件中进行分析. 或者用gdb提前跟踪将要出错的进程(那就太复杂了).

有没有什么更便捷的方式, 让SQL执行出错(但是数据库没有崩溃)时打印堆栈信息呢?

有个patch, 下面就看看怎么做?

以下内容翻译自:

  • https://www.enterprisedb.com/blog/stack-traces-postgres-errors-backtracefunctions

开始吧

如果 Postgres 崩溃了,你可以用 gdb 获取堆栈跟踪。但是如何调试不会导致 Postgres 崩溃的错误呢?

让我们获取 Postgres 17 源码并使用调试符号构建它。

代码语言:javascript
复制
$ 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 install  

创建并启动数据库。 ··· ./build/bin/pg_ctl -D $(pwd)/testdb -l logfile start ···

并用 psql 连接到它。

代码语言:javascript
复制
$ ./build/bin/psql postgres  
psql (17.5)  
Type "help" for help.  
postgres=#  

让我们通过查询不存在的表来触发错误。

代码语言:javascript
复制
postgres=# SELECT * FROM nothere;  
ERROR:  relation "nothere" does not exist  
LINE 1: SELECT * FROM nothere;  
                     ^  
postgres=#  

这不是我们通常尝试调试的ERROR类型,但它很简单,我的目标是演示这个过程。

在我了解得更多ERROR之前,如果给我一些通用的东西,我会抓住字符串中非动态的部分用grep在代码中查找。

代码语言:javascript
复制
$ 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 之后,我们也许能找到它。也可能不会。

了解ERROR错误出自哪个函数的一个直接方法是将VERBOSITY设置为verbose。启用此选项后,将告诉我们错误来自哪个函数名和c文件(这本身就解决了很大一部分原始问题)。

代码语言:javascript
复制
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:1452  

但我上周值班的时候也刚了解了GUC backtrace_functions。你可以用这个 GUC 让 Postgres 在发生错误时打印堆栈跟踪信息。这太有用了!

详见:

https://www.postgresql.org/docs/current/runtime-config-developer.html

诀窍在于,你必须明确指定哪些函数会生成你希望获取的堆栈跟踪日志。我猜这是为了避免堆栈跟踪日志泛滥。也就是说,只有当日志来自某个函数(以逗号分隔的值命名)时,backtrace_functions 才会打印堆栈跟踪。

现在我们先用\set VERBOSITY verbose知道了日志来自的确切函数:parserOpenTable。所以我们可以设置backtrace_functions = parserOpenTable并重新加载 Postgres 配置。

代码语言:javascript
复制
postgres=# ALTER SYSTEM SET backtrace_functions='parserOpenTable';  
ALTER SYSTEM  
postgres=# SELECT pg_reload_conf();  
pg_reload_conf  
----------------  
t  
(1 row)  

再次运行该失败的查询:

代码语言:javascript
复制
postgres=# SELECT * FROM nothere;  
ERROR:  42P01: relation "nothere" does not exist  
LINE 1: SELECT * FROM nothere;  
                     ^  
LOCATION:  parserOpenTable, parse_relation.c:1452  

我们将在中看到此错误的堆栈跟踪logfile!

代码语言:javascript
复制
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 + 2476  

还有一个补丁,可以让你自动打印所有错误的堆栈跟踪。这对于自动化测试环境尤其有用,因为这类环境错误很少发生,而且调试起来很繁琐。我期待这个补丁最终能够发布!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 digoal德哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用开发者参数 backtrace_functions 对 Postgres 错误进行实时堆栈跟踪
  • 开始吧
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档