首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >让backtrace打印更便捷--从backtrace_functions到backtrace_errors

让backtrace打印更便捷--从backtrace_functions到backtrace_errors

作者头像
NickYoung
发布2026-07-09 16:25:47
发布2026-07-09 16:25:47
20
举报

封面图是关山草原美景,可能有些朋友不知道或没去过,陕西和甘肃部分地区的朋友应该很熟悉。国家AAAA级旅游景区,风景确实不错,“关山牧场郁郁葱葱,林草山溪相得益彰” 。周末回了趟老家顺路去了下关山草原,潇洒的是跑马场骑了一圈,不幸的是有点儿晒伤了。大家有空了去游玩,一定要做好防晒。

言归正传,德哥最近写了一篇PG实时堆栈跟踪[1],其中介绍了通过配置内核函数名到backtrace_functions参数,当发生错误时,就会打印堆栈信息了。也就是说会自动打印已配置的内核函数的错误堆栈。确实比之前自行debug要方便一些。

同时文中提到社区还有一个补丁,可以自动打印所有错误的堆栈跟踪。

虽然我没看这个补丁,不过,这不巧了么。在PGCM课程中,有学员认为backtrace_functions参数配置很麻烦,且不够灵活。为什么不能搞个开关可以自动打印所有错误的堆栈呢。老杨觉得很有道理,所以我DIY了一个参数backtrace_errors,用来实现这个逻辑。

顺便提一下,本周六下午PG技术峰会哈尔滨站我将会分享相关的内容,希望大家多多关注。

backtrace_functions的局限性

以下均为个人理解和看法,或许会有偏差。

第一,我们无法提前预估我们将来会在哪个内核函数发生错误,当发生错误时,可能得多次复现先确认报错的内核函数,并将其配置到backtrace_functions 再次复现报错才可记录backtrace;

第二,我想分析很多个内核函数报错时,就需要配置很多个内核函数到backtrace_functions,确实不太方便。

所以,为什么不做一个简单的开关呢,只要报错就记录backtrace。

backtrace_functions原理

backtrace_functions在ConfigureNamesString数组中,入参类型为string,有对应的check函数进行处理,生效级别为PGC_SUSET即superuser set生效。

代码语言:javascript
复制
 {
                {"backtrace_functions", PGC_SUSET, DEVELOPER_OPTIONS,
                        gettext_noop("Log backtrace for errors in these functions."),
                        NULL,
                        GUC_NOT_IN_SAMPLE
                },
                &backtrace_functions,
                "",
                check_backtrace_functions, assign_backtrace_functions, NULL
        },

在errfinish中,当发生错误时,同时backtrace_functions非空,且发生错误的函数和参数配置相匹配时则调用set_backtrace函数。

代码语言:javascript
复制
void
errfinish(const char *filename, int lineno, const char *funcname)
{
/* 省略 */
/* Collect backtrace, if enabled and we didn't already */
if (!edata->backtrace &&
  edata->funcname &&
  backtrace_functions &&
  matches_backtrace_functions(edata->funcname))
  set_backtrace(edata, 2);
/* 省略 */

}

set_backtrace函数调用glibc的backtrace函数对发生错误的backtrace进行打印。

代码语言:javascript
复制
static void
set_backtrace(ErrorData *edata, int num_skip)
{
 StringInfoData errtrace;

 initStringInfo(&errtrace);

#ifdef HAVE_BACKTRACE_SYMBOLS
 {
void    *buf[100];
int   nframes;
char   **strfrms;

  nframes = backtrace(buf, lengthof(buf));
  strfrms = backtrace_symbols(buf, nframes);
if (strfrms == NULL)
   return;

for (int i = num_skip; i < nframes; i++)
   appendStringInfo(&errtrace, "\n%s", strfrms[i]);
free(strfrms);
 }
#else
 appendStringInfoString(&errtrace,
         "backtrace generation is not supported by this installation");
#endif

 edata->backtrace = errtrace.data;
}

方案

参考backtrace_functions,新增一个参数backtrace_errors,实现打印error backtrace的能力。

为bool类型,默认值为false,生效级别为PGC_SUSET。

errfinish中,当发生错误并且backtrace_errors为true时,调用set_backtrace函数记录backtrace。

验证

backtrace_functions未配置,打开backtrace_errors,在postgres库中执行drop database postgres报错"cannot drop the currently open database"

代码语言:javascript
复制
postgres=# show backtrace_functions ;
 backtrace_functions 
---------------------
 
(1 row)

postgres=# set backtrace_errors to on;
SET
postgres=# drop database postgres;
ERROR:  cannot drop the currently open database
postgres=#

报错的backtrace已经记录到日志中。

代码语言:javascript
复制
2025-05-15 00:12:33.746 CST [3887265] ERROR:  cannot drop the currently opendatabase
2025-05-15 00:12:33.746 CST [3887265] BACKTRACE:  
        postgres: postgres postgres [local] DROPDATABASE(dropdb+0x22a) [0x66d457]
        postgres: postgres postgres [local] DROPDATABASE(DropDatabase+0x12c) [0x66e524]
        postgres: postgres postgres [local] DROPDATABASE(standard_ProcessUtility+0x6c4) [0x98dbec]
        /data/postgres/postgresql-17.4/pgapp/lib/pg_stat_statements.so(+0x4673) [0x7fdee6961673]
        postgres: postgres postgres [local] DROPDATABASE(ProcessUtility+0x52) [0x98d4f0]
        postgres: postgres postgres [local] DROPDATABASE() [0x98c423]
        postgres: postgres postgres [local] DROPDATABASE() [0x98c622]
        postgres: postgres postgres [local] DROPDATABASE(PortalRun+0x292) [0x98bc16]
        postgres: postgres postgres [local] DROPDATABASE() [0x985822]
        postgres: postgres postgres [local] DROPDATABASE(PostgresMain+0x720) [0x989fa5]
        postgres: postgres postgres [local] DROPDATABASE() [0x982324]
        postgres: postgres postgres [local] DROPDATABASE(postmaster_child_launch+0xd4) [0x8c174f]
        postgres: postgres postgres [local] DROPDATABASE() [0x8c6cfb]
        postgres: postgres postgres [local] DROPDATABASE() [0x8c44b3]
        postgres: postgres postgres [local] DROPDATABASE(PostmasterMain+0x1239) [0x8c3e77]
        postgres: postgres postgres [local] DROPDATABASE() [0x79642b]
        /lib64/libc.so.6(__libc_start_main+0xe5) [0x7fdee8f717e5]
        postgres: postgres postgres [local] DROPDATABASE(_start+0x2e) [0x4904fe]
2025-05-15 00:12:33.746 CST [3887265] STATEMENT:  dropdatabase postgres;

总结

新增参数backtrace_errors,实现只要报错就可以打印backtrace,对比backtrace_functions参数,某种程度上来说算是一种提升。

Reference

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

本文分享自 PostgreSQL运维之道 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 封面图是关山草原美景,可能有些朋友不知道或没去过,陕西和甘肃部分地区的朋友应该很熟悉。国家AAAA级旅游景区,风景确实不错,“关山牧场郁郁葱葱,林草山溪相得益彰” 。周末回了趟老家顺路去了下关山草原,潇洒的是跑马场骑了一圈,不幸的是有点儿晒伤了。大家有空了去游玩,一定要做好防晒。
    • backtrace_functions的局限性
    • backtrace_functions原理
    • 方案
    • 验证
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档