2010-04-01 50 views
2

我正在寫一個任務,它涉及在Solaris機器上爲PostgreSQL添加一些功能。作爲作業的一部分,我們需要在客戶端打印一些信息(例如:使用elog。)如何暫時將printf輸出重定向到c字符串?

PostgreSQL已經有很多幫助方法可以打印出所需的信息,但是,幫助程序方法是打包數百printf調用,而elog方法僅適用於c風格的字符串。

有沒有我的方式,我可以暫時將printf調用重定向到一個緩衝區,所以我可以很容易地通過elog發送到客戶端?

如果這是不可能的,那麼修改輔助方法最終以緩衝區爲輸出的最簡單方法是什麼?

回答

7

如果您定義自己的printf版本並將其鏈接到之前到libc版本,您的版本將取代標準版本。

您還應該能夠使用LD_PRELOAD加載定義了printf的庫來取代標準版本。

要編寫自己的printf,你將要使用stdarg頭文件功能:當最終格式化輸出比LARGESIZE更大

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; 
} 

這個簡單的版本將截斷數據。如果你不想這樣做,你也可以先用NULL緩衝區調用vsnprintf來獲得最終大小,做一個動態分配,然後再調用vsprintf來格式化緩衝區。

+0

由於這是一項任務,我只需要提交源文件,我無法控制什麼時候鏈接。 – 2010-04-01 18:55:37

+0

@BenS - 如果你把printf放在你的源文件中,它應該可以正常工作。 – 2010-04-01 18:56:20

+0

我認爲@R塞繆爾是正確的,libc最後被鏈接,對嗎? – 2010-04-01 18:59:25

2

最簡單的方法是修改輔助方法來調用sprintf()。你是否可以輕易破解,我不知道。也許

#define printf(...) sprintf(buffer, __VA_ARGS__) 

會爲你做。您仍然需要爲每個幫助函數定義buffer,並將其內容返回給關心它們的人。

+0

是的,在兩個文件中有大約十幾個幫助方法,所以在這條路線上還有很多工作要做。另外,不會多次調用,然後覆蓋以前的sprintf?或者sprintf追加? – 2010-04-01 18:42:00

+0

@本S,也許已經有你想要的功能嗎?您可以追加'sprintf()',因爲它返回打印的字符數。如果每個函數都有一個緩衝區,那麼可能不會很難實現。 – 2010-04-01 18:44:29

1

如果你能忍受使用臨時文件,你可以重定向與freopen()調用標準進行: -

newstdout = freopen("/tmp/log", "w", stdout); 

這將迫使所有的printf的寫入到/ tmp /登錄控制檯,而不是輸出。在一些方便點以後在你的程序,你可以再打開同一個文件進行讀取: -

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()函數可用於獲取臨時文件的名稱。

4

你錯了— elog支持格式化字符串就像printf。下面是Postgres的源代碼的例子:

elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i); 

因此,所有你需要的是增加elog那裏是printf使用相同的參數。

相關問題