首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用 backtrace_functions 对 Postgres 错误进行堆栈跟踪

使用 backtrace_functions 对 Postgres 错误进行堆栈跟踪

作者头像
小徐
发布2025-09-11 19:08:55
发布2025-09-11 19:08:55
1300
代码可运行
举报
文章被收录于专栏:GreenplumGreenplum
运行总次数:0
代码可运行

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

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

代码语言:javascript
代码运行次数:0
运行
复制
$ 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

创建并启动数据库。

代码语言:javascript
代码运行次数:0
运行
复制
$ ./build/bin/initdb testdb
$ ./build/bin/pg_ctl -D $(pwd)/testdb -l logfile start

并使用 psql 连接到它。

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

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

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

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

在我更好地了解情况之前,如果遇到某个通用的ERROR,我会提取字符串中不变的部分,然后用git grep命令搜索它们。

代码语言:javascript
代码运行次数:0
运行
复制
$ 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 foo,我们也许能够找到它。或者我们可能不会。

了解ERROR源自哪个函数的一个直接方法是在psql 中将VERBOSITY 设置为verbose。开启此设置后,psql 会告诉我们错误源自的函数名和文件(嘿,这本身就解决了部分初始问题)。

代码语言:javascript
代码运行次数:0
运行
复制
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

但我上周在电话会议期间也刚刚了解到了backtrace_functions 这个 GUC(运行时参数)。你可以使用这个 GUC 让 Postgres 在发生错误时打印堆栈跟踪信息。这非常有用!

诀窍在于,您必须准确指定哪些函数生成日志,您关心为其获取堆栈跟踪。我想这是为了避免使用堆栈跟踪发送垃圾邮件日志。也就是说,只有当一个函数(以逗号分隔的值命名 backtrace_functions)是日志的来源函数。

但是通过 \set VERBOSITY verbose,我们现在知道日志的确切来源函数:parserOpenTable。因此,我们可以将backtrace_functions设置为 parserOpenTable 并重新加载 Postgres 配置。

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

再次运行该失败的查询:

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

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

代码语言:javascript
代码运行次数:0
运行
复制
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

还有一个潜在补丁,可让您自动打印所有错误的堆栈跟踪。这对于自动化测试环境尤其有用,在这些环境中,错误可能不常出现且调试起来很繁琐。我期待该补丁最终能得以应用!

参考文档 :enterprisedb [1]。

引用链接

[1] enterprisedb : https://www.enterprisedb.com/blog/stack-traces-postgres-errors-backtracefunctions

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

本文分享自 河马coding 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引用链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档