如果你自己創造的記錄,你可以先創建File
對象,然後用它來創建記錄器,並將其分配給$stderr
:
log_file = File.new('foo.log', 'a')
logger = Logger.new(log_file, 'weekly')
$stderr = log_file #usually no need to use reopen
注意,這將導致日誌輸出與$stderr
的輸出混淆在一起,如果您正在解析日誌文件,並希望它處於某種格式(這也會發生在您的解決方案中),則可能會導致問題。
如果您沒有底層文件,但只是從其他地方收到logger
,則會更棘手。需要的是IO
類似的對象,可以分配給$stderr
並將寫入的任何東西傳遞給記錄器。不幸的是,Ruby中的IO
類與底層I/O系統(文件描述符等)緊密相關,並且沒有可用於創建輸入和輸出流的通用接口。 (StringIO
是值得注意的例外)。
然而,大多數,如果不是全部,對IO
的輸出方式,最終都要經過#write
,所以通過重寫這個方法,你可以親近你以後:
class IOToLog < IO
def initialize(logger)
@logger = logger
end
def write(string)
#assume anything written to stderr is an error
@logger.error(message)
end
end
logger = get_logger_from_somewhere
$stderr = IOToLog.new(logger)
現在什麼寫入$stderr
將最終轉到日誌文件。格式不過會有點奇怪。任何時候任何寫入方法都會調用#write
將在日誌文件中創建一個新條目。例如,調用數組的#puts
將爲數組的每個條目調用#write
,並在每個條目之間再次使用換行符,從而生成2n-1條日誌條目,其中n-1條將爲空。
你可以使覆蓋的#write
方法更復雜來處理這個問題,也許使用內部緩衝區,並且只在你認爲你有完整的消息時調用記錄器。或者,您可以重寫個別方法以自行寫入記錄器。如果你這樣做,IOToLog
類不一定要從IO
繼承。
您最好的解決方案將取決於您希望標準錯誤輸出出現在日誌文件中,您的程序如何使用$stderr
以及您想要從IO
執行方法需要執行多少工作。
很好的答案,謝謝!在我的情況下,我正在創建記錄器,以便您的第一個解決方案乾淨而優雅。我特別喜歡你已經包含了另一種情況的解決方法。 (雖然在這種情況下,我可能會主張我直接進入並直接抓取文件。) – Phrogz 2012-03-09 23:24:55
第二種方法在jruby上不適用於我。我得到以下錯誤:(Errno :: EBADF)錯誤的文件描述符 – 2013-01-02 13:31:29
應該有'@ logger.error(string)'我認爲 – lojza 2017-06-21 12:51:41