我正在编写一个分配,其中包括在Solaris机器上向PostgreSQL添加一些功能。作为转让的一部分,我们需要在客户端打印一些信息(即:使用elog
。)
PostgreSQL已经有很多帮助方法可以打印出所需的信息,但是,帮助方法包含了数百个printf
个调用,而elog
方法只适用于c风格的字符串。
我是否可以暂时将printf
次呼叫重定向到缓冲区,以便我可以轻松地通过elog
将其发送到客户端?
如果那是不可能的,那么修改辅助方法以最终将缓冲区作为输出的最简单方法是什么?
答案 0 :(得分:7)
如果您定义了自己的printf版本并将其链接到之前到libc版本,那么您的版本将取代标准版本。
您还应该能够通过使用LD_PRELOAD来加载已定义printf的库来取代标准版本。
要编写自己的printf,您需要使用stdarg功能:
int printf(const char *fmt, ...)
{
int rv;
va_list ap;
va_start(ap, fmt);
if (redirect_printf)
{
#ifdef HAVE_VLOG
// If you have a vlog function that takes a va_list
vlog(fmt, ap);
rv = ...;
#else
char buffer[LARGESIZE];
rv = vsnprintf(buffer, sizeof(buffer), fmt, ap);
log(buffer);
#endif;
}
else
{
rv = vprintf(fmt, ap);
}
return rv;
}
当最终格式化输出大于LARGESIZE
时,此简单版本将截断数据。如果你不想这样,你也可以先用NULL缓冲区调用vsnprintf
来获得最终大小,进行动态分配,然后再调用vsprintf
来格式化缓冲区。
答案 1 :(得分:4)
你错了 - elog
支持格式字符串,就像printf一样。这是Postgres源代码的一个例子:
elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i);
所以您只需要使用相同的参数在elog
处添加printf
。
答案 2 :(得分:2)
最简单的方法是修改辅助方法以调用sprintf()
。我不知道你是否可以轻易地破解它。也许
#define printf(...) sprintf(buffer, __VA_ARGS__)
会为你做的。您仍然需要为每个帮助函数定义buffer
,并将其内容返回给关心它们的人。
答案 3 :(得分:1)
如果您可以容忍使用临时文件,则可以通过freopen()
调用重定向标准: -
newstdout = freopen("/tmp/log", "w", stdout);
这将强制将所有printf写入/ tmp / log而不是控制台输出。在程序稍后的某个方便点,您可以打开相同的文件进行阅读: -
readfd = fopen("/tmp/log", "r");
并转发使用以下内容添加的内容: -
void forward_to_elog(void)
{
int bytesread;
char buf[100];
memset(buf,0,100);
do {
memset(buf,0,100);
bytesread = fread(buf, sizeof(buf)-1, 1, readfd);
/* call elog(buf) */ ;
} while(bytesread);
}
如果您打开文件,可以多次致电forward_to_elog()
以逐步转发已添加的内容。
tmpnam()
函数可用于获取临时文件的名称,如果您不想静态编码一个。