2009-12-30 48 views
6

我的Java應用程序使用JNI調用C編寫的庫。此本機庫將錯誤記錄到stderr,但我想通過我的log4j記錄器以某種方式重定向錯誤流。這可能嗎?通過log4j發送JNI C stderr/stdout

C庫是外部的 - 我沒有源代碼,所以無法更改它。

感謝

+0

JNI圖層是您的應用程序的一部分還是外部工具包的一部分? – PSpeed 2009-12-30 23:09:17

+0

這也是外部工具包的一部分。 – dogbane 2009-12-30 23:17:09

+0

您調用外部代碼的粒度是多少,以及有多少數據來回傳遞?換句話說,你能把這項工作作爲一個孩子的過程嗎?重定向你不能控制的C代碼的stdout或stderr是非常困難的。我之前認爲我已經完成了它,但自從我編寫了那種C代碼以來,至少已經有10年了,我可以在網上找到的所有代碼都是關於將其重定向到文件的。 – PSpeed 2009-12-30 23:32:19

回答

3

注:我沒有嘗試過這個答案;因人而異。

POSIX方法freopen將更改與流關聯的底層文件。正如手冊頁所述:「freopen()函數的主要用途是更改與標準文本流(stderr,stdin或stdout)關聯的文件」。

所以,你可以創建自己的JNI庫,它只是將流重定向到一個文件中。 然而,有幾個嚴重的障礙,以使這項工作:

  1. 你需要確保你的Java程序 本身不使用標準 流,因爲他們會被重定向 過。 的解決方法是在程序啓動時將System.out和 更改爲其他內容。
  2. 第三方庫可能繞過標準 文本流,並直接寫入底層文件描述符 。這不太可能,但可能是 。我不能 記得freopen()只是 更改緩衝流使用的文件描述符 ,或者實際上 重新打開底層的fd。
  3. 你會 仍然有問題連接 更改爲「文件」到記錄器。

最後一點是迄今最大的:stdio寫入OS級文件描述符。您將不得不創建一些Java級代碼來讀取該描述符並寫入日誌。我的第一個想法是,你必須使用一個命名管道,然後啓動一個新的Java線程來讀取該管道。但是這不能移植到不同的操作系統,並且你會在你的程序配置中管理管道名稱。

假設這是一個服務器程序,並且本身並不處理標準IO流,我認爲最好的解決方案是使用控制檯記錄器配置Log4J,並將所有控制檯輸出重定向到一個文件。

或者與編寫庫的人交談,讓他們添加可配置的日誌記錄。

-1

我的C是有點生疏,但它是可能的,因爲你可以從通過JNI一個C中調用PrinStream方法。但是當流寫入時,你必須找到一種方法來掛鉤。

更新:這可以幫助你與掛鉤到標準輸出從C:

http://www.gnu.org/software/hello/manual/libc/Hook-Functions.html

+0

謝謝,但不幸的是我不能改變C庫,因爲它不是我的。 – dogbane 2009-12-30 22:57:00