有點像記錄器中的三通功能。我怎樣纔能有紅寶石記錄器日誌輸出到標準輸出以及文件?
回答
您可以編寫一個僞IO
類,它將寫入多個IO
對象。喜歡的東西:
class MultiIO
def initialize(*targets)
@targets = targets
end
def write(*args)
@targets.each {|t| t.write(*args)}
end
def close
@targets.each(&:close)
end
end
然後設置爲你的日誌文件:
log_file = File.open("log/debug.log", "a")
Logger.new MultiIO.new(STDOUT, log_file)
每次Logger
電話puts
您MultiIO
對象,其將同時寫入STDOUT
和你的日誌文件。
編輯:我繼續前進,想通了接口的其餘部分。日誌設備必須響應write
和close
(而不是puts
)。只要MultiIO
對這些響應並將它們代理到真正的IO對象,這應該工作。
的提示,如果你看看記錄儀的監視器,你會看到這會弄亂日誌的旋轉。如果log.respond_to?(:write)和log.respond_to ?,則返回false。如果log.respond_to?(:write)和log.respond_to? (:關閉) \t @dev = log else \t @dev = open_logfile(log) \t @dev。sync = true \t @filename = log \t @shift_age = opt [:shift_age] || 7 \t @shift_size = opt [:shift_size] || 1048576 結束 結束' – JeffCharter
注意在Ruby 2.2中,'@ targets.each(&:close)'折舊。 – xis
@大衛的解決方案非常好。我已經根據他的代碼爲多個目標製作了一個通用委託類。
require 'logger'
class MultiDelegator
def initialize(*targets)
@targets = targets
end
def self.delegate(*methods)
methods.each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
self
end
class <<self
alias to new
end
end
log_file = File.open("debug.log", "a")
log = Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)
您還可以添加多個設備的日誌記錄功能,直接進入記錄儀:
require 'logger'
class Logger
# Creates or opens a secondary log file.
def attach(name)
@logdev.attach(name)
end
# Closes a secondary log file.
def detach(name)
@logdev.detach(name)
end
class LogDevice # :nodoc:
attr_reader :devs
def attach(log)
@devs ||= {}
@devs[log] = open_logfile(log)
end
def detach(log)
@devs ||= {}
@devs[log].close
@devs.delete(log)
end
alias_method :old_write, :write
def write(message)
old_write(message)
@devs ||= {}
@devs.each do |log, dev|
dev.write(message)
end
end
end
end
例如:
logger = Logger.new(STDOUT)
logger.warn('This message goes to stdout')
logger.attach('logfile.txt')
logger.warn('This message goes both to stdout and logfile.txt')
logger.detach('logfile.txt')
logger.warn('This message goes just to stdout')
這裏的另一種實現方式,通過啓發@ jonas054的回答。
這使用類似於Delegator
的模式。這樣,您就不必列出所有要委派的方法,因爲它會委派任何目標對象定義的所有方法:
class Tee < DelegateToAllClass(IO)
end
$stdout = Tee.new(STDOUT, File.open("#{__FILE__}.log", "a"))
您應該能夠爲使用與記錄儀好。
delegate_to_all.rb可從這裏:https://gist.github.com/TylerRick/4990898
這似乎是一個超級優雅的方式來解決問題。 –
雖然我很喜歡的其他建議,我發現我有同樣的問題,但希望有STDERR和文件不同的日誌記錄級別的能力(比如我可以與更大的日誌框架,如NLog)。我結束了路由策略的記錄水平,而不是在IO級複用,使每個記錄然後可以在獨立的日誌級別操作:
class MultiLogger
def initialize(*targets)
@targets = targets
end
%w(log debug info warn error fatal unknown).each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
end
$stderr_log = Logger.new(STDERR)
$file_log = Logger.new(File.open('logger.log','a'))
$stderr_log.level = Logger::INFO
$file_log.level = Logger::DEBUG
$log = MultiLogger.new($stderr_log, $file_log)
我去了同樣的想法「委派所有子元素的方法「,其他人已經探索過,但是爲每個人返回最後一次調用方法的返回值。 如果我沒有,它破壞了logger-colors
這期待Integer
和地圖是返回Array
。
class MultiIO
def self.delegate_all
IO.methods.each do |m|
define_method(m) do |*args|
ret = nil
@targets.each { |t| ret = t.send(m, *args) }
ret
end
end
end
def initialize(*targets)
@targets = targets
MultiIO.delegate_all
end
end
這將重新調用每個方法到所有目標,並只返回最後一次調用的返回值。另外,如果你想要顏色,STDOUT或STDERR必須放在最後,因爲它只有兩個顏色應該輸出。但是,它也會將顏色輸出到您的文件。
logger = Logger.new MultiIO.new(File.open("log/test.log", 'w'), STDOUT)
logger.error "Roses are red"
logger.unknown "Violets are blue"
我已經寫了一個小RubyGem,讓你做一些這些事情:
# Pipe calls to an instance of Ruby's logger class to $stdout
require 'teerb'
log_file = File.open("debug.log", "a")
logger = Logger.new(TeeRb::IODelegate.new(log_file, STDOUT))
logger.warn "warn"
$stderr.puts "stderr hello"
puts "stdout hello"
您可以在github代碼:我認爲你的標準輸出用於teerb
提出關鍵的運行時信息和錯誤。
於是我就用
$log = Logger.new('process.log', 'daily')
登錄調試和定期日誌記錄,然後寫了幾
puts "doing stuff..."
,我需要看到STDOUT信息,我的腳本是運行在所有!
呸,只是我的10美分:-)
如果你在Rails的3或4,爲this blog post指出,Rails 4 has this functionality built in。所以,你可以這樣做:
# config/environment/production.rb
file_logger = Logger.new(Rails.root.join("log/alternative-output.log"))
config.logger.extend(ActiveSupport::Logger.broadcast(file_logger))
或者如果你on Rails的3,你可以反向移植它:
# config/initializers/alternative_output_log.rb
# backported from rails4
module ActiveSupport
class Logger < ::Logger
# Broadcasts logs to multiple loggers. Returns a module to be
# `extended`'ed into other logger instances.
def self.broadcast(logger)
Module.new do
define_method(:add) do |*args, &block|
logger.add(*args, &block)
super(*args, &block)
end
define_method(:<<) do |x|
logger << x
super(x)
end
define_method(:close) do
logger.close
super()
end
define_method(:progname=) do |name|
logger.progname = name
super(name)
end
define_method(:formatter=) do |formatter|
logger.formatter = formatter
super(formatter)
end
define_method(:level=) do |level|
logger.level = level
super(level)
end
end
end
end
end
file_logger = Logger.new(Rails.root.join("log/alternative-output.log"))
Rails.logger.extend(ActiveSupport::Logger.broadcast(file_logger))
是否適用於導軌或導軌? –
它基於ActiveSupport,所以如果你已經有了這個依賴關係,你可以像上面那樣擴展任何'ActiveSupport :: Logger'實例。 – phillbaker
謝謝,這很有幫助。 – Lucas
另一種方式。 如果您正在使用標記記錄和需要標籤的另一個日誌文件以及,你可以做這樣
# backported from rails4
# config/initializers/active_support_logger.rb
module ActiveSupport
class Logger < ::Logger
# Broadcasts logs to multiple loggers. Returns a module to be
# `extended`'ed into other logger instances.
def self.broadcast(logger)
Module.new do
define_method(:add) do |*args, &block|
logger.add(*args, &block)
super(*args, &block)
end
define_method(:<<) do |x|
logger << x
super(x)
end
define_method(:close) do
logger.close
super()
end
define_method(:progname=) do |name|
logger.progname = name
super(name)
end
define_method(:formatter=) do |formatter|
logger.formatter = formatter
super(formatter)
end
define_method(:level=) do |level|
logger.level = level
super(level)
end
end # Module.new
end # broadcast
def initialize(*args)
super
@formatter = SimpleFormatter.new
end
# Simple formatter which only displays the message.
class SimpleFormatter < ::Logger::Formatter
# This method is invoked when a log event occurs
def call(severity, time, progname, msg)
element = caller[4] ? caller[4].split("/").last : "UNDEFINED"
"#{Thread.current[:activesupport_tagged_logging_tags]||nil } # {time.to_s(:db)} #{severity} #{element} -- #{String === msg ? msg : msg.inspect}\n"
end
end
end # class Logger
end # module ActiveSupport
custom_logger = ActiveSupport::Logger.new(Rails.root.join("log/alternative_#{Rails.env}.log"))
Rails.logger.extend(ActiveSupport::Logger.broadcast(custom_logger))
在此之後,你會在替代記錄器獲取的uuid標籤
["fbfea87d1d8cc101a4ff9d12461ae810"] 2015-03-12 16:54:04 INFO logger.rb:28:in `call_app' --
["fbfea87d1d8cc101a4ff9d12461ae810"] 2015-03-12 16:54:04 INFO logger.rb:31:in `call_app' -- Started POST "/psp/entrypoint" for 192.168.56.1 at 2015-03-12 16:54:04 +0700
希望這有助於某人。
對於那些誰喜歡簡單:
log = Logger.new("| tee test.log") # note the pipe ('|')
log.info "hi" # will log to both STDOUT and test.log
或打印在記錄器格式化消息:
log = Logger.new("test.log")
log.formatter = proc do |severity, datetime, progname, msg|
puts msg
msg
end
log.info "hi" # will log to both STDOUT and test.log
我實際使用這種技術打印到日誌文件,雲記錄器服務(logentries)以及它是否是開發環境 - 也可以打印到STDOUT。
您是否僅限於標準記錄器?
如果不是你可以使用log4r:
require 'log4r'
LOGGER = Log4r::Logger.new('mylog')
LOGGER.outputters << Log4r::StdoutOutputter.new('stdout')
LOGGER.outputters << Log4r::FileOutputter.new('file', :filename => 'test.log') #attach to existing log-file
LOGGER.info('aa') #Writs on STDOUT and sends to file
一個優點:你也可以定義不同的日誌級別stdout和文件。
@ jonas054上面的答案很好,但它污染MultiDelegator
類與每個新的代表。如果您多次使用MultiDelegator
,它將繼續向課程添加方法,這是不可取的。 (請參閱下面的示例)
以下是相同的實現,但使用匿名類,以便方法不污染委託人類。
class BetterMultiDelegator
def self.delegate(*methods)
Class.new do
def initialize(*targets)
@targets = targets
end
methods.each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
class <<self
alias to new
end
end # new class
end # delegate
end
下面是原來實行的方法的污染,與修改後的實施對比的例子:
tee = MultiDelegator.delegate(:write).to(STDOUT)
tee.respond_to? :write
# => true
tee.respond_to? :size
# => false
所有高於良好。 tee
有一個write
方法,但沒有size
方法如預期。現在,考慮當我們創建另一個代表:
tee2 = MultiDelegator.delegate(:size).to("bar")
tee2.respond_to? :size
# => true
tee2.respond_to? :write
# => true !!!!! Bad
tee.respond_to? :size
# => true !!!!! Bad
哦,不,tee2
響應size
如預期,但它也迴應write
因爲第一個委託。由於方法污染,即使tee
現在也響應size
。
此相反的是匿名一流的解決方案,如預期的一切:
see = BetterMultiDelegator.delegate(:write).to(STDOUT)
see.respond_to? :write
# => true
see.respond_to? :size
# => false
see2 = BetterMultiDelegator.delegate(:size).to("bar")
see2.respond_to? :size
# => true
see2.respond_to? :write
# => false
see.respond_to? :size
# => false
一個選項可用;-)
require 'logger'
class MultiDelegator
def initialize(*targets)
@targets = targets
end
def method_missing(method_sym, *arguments, &block)
@targets.each do |target|
target.send(method_sym, *arguments, &block) if target.respond_to?(method_sym)
end
end
end
log = MultiDelegator.new(Logger.new(STDOUT), Logger.new(File.open("debug.log", "a")))
log.info('Hello ...')
快速和骯髒的(參考:https://coderwall.com/p/y_b3ra/log-to-stdout-and-a-file-at-the-same-time)
require 'logger'
ll=Logger.new('| tee script.log')
ll.info('test')
http://stackoverflow.com/a/34026278/322020 – Nakilon
我喜歡MultiIO的方法。它適用於Ruby Logger。如果您使用純粹的IO它會停止工作,因爲它缺少一些IO對象應具有的方法。 管道之前提到這裏:How can I have ruby logger log output to stdout as well as file?。這裏是最適合我的。
def watch(cmd)
output = StringIO.new
IO.popen(cmd) do |fd|
until fd.eof?
bit = fd.getc
output << bit
$stdout.putc bit
end
end
output.rewind
[output.read, $?.success?]
ensure
output.close
end
result, success = watch('./my/shell_command as a String')
注意我知道這並不直接回答這個問題,但它有很大關係。每當我搜索輸出到多個IO時,我都會遇到這個線程。所以,我希望你也發現它也很有用。
- 1. Python日誌記錄到標準輸出和日誌文件
- 2. 我怎樣才能找到紅寶石
- 3. 紅寶石IO.popen標準輸出緩衝
- 4. pytest日誌記錄到文件和標準輸出
- 5. 寫紅寶石輸出到文件
- 6. 紅寶石每個 - 我怎麼能輸出所有市場
- 7. 我怎樣才能「再次打開」標準輸出?
- 8. 在Chrome中,我怎樣才能得到JavaScript控制檯輸出到標準輸出/標準錯誤
- 9. 我怎樣才能達到標準輸入/輸出通過gdbserver的會話
- 10. 從標準輸入讀取和打印到紅寶石標準輸出
- 11. Scala日誌記錄,將控制檯輸出直接輸出到日誌文件
- 12. 我怎樣才能找出ac#項目文件(.csproj)的輸出
- 13. 我應該怎麼做才能修復playframework 2中的日誌記錄輸出?
- 14. 紅寶石:捕獲輸出
- 15. 記錄標準輸出到gunicorn訪問日誌?
- 16. Java日誌API,禁用記錄到標準輸出
- 17. Grails:將調試日誌記錄發送到標準輸出
- 18. 我怎樣才能紅寶石使用其輸入輸出定義的格式的方法
- 19. 紅寶石記錄器 - 何時關閉日誌文件
- 20. 爲什麼記錄器輸出到標準輸出重定向到文件?
- 21. Calllogs返回所有日誌調用以及短信日誌,我怎樣才能過濾只有通話記錄?
- 22. 我怎樣才能得到JSON格式的遊標輸出?
- 23. NHibernate的日誌到標準輸出
- 24. 我怎樣才能得到以下輸出?
- 25. 我可以禁用紅寶石記錄器的日誌標頭嗎?
- 26. 紅寶石輸入輸出問題
- 27. 紅寶石+ Testunit + ci_reporter:沒有XML輸出
- 28. 輸出線到線的紅寶石
- 29. 我們怎樣才能看到沒有矩形框的輸出
- 30. 去日誌記錄到多個輸出
添加'| | tee'在文件爲我工作之前,所以'Logger.new(「| tee test.log」)'。 **注意管道。**這是來自https://coderwall.com/p/y_b3ra/log-to-stdout-and-a-file-at-the-same-time – mjwatts