Hinzufügen, | teebevor die Datei für mich funktioniert hat, also Logger.new("| tee test.log"). Beachten Sie das Rohr. Dies war aus einem Tipp auf coderwall.com/p/y_b3ra/…
Mike W
@mjwatts Verwenden Sie diese Option tee --append test.log, um Überschreibungen zu verhindern.
Fangxing
Antworten:
124
Sie können eine Pseudoklasse IOschreiben, die in mehrere IOObjekte schreibt . Etwas wie:
classMultiIOdef initialize(*targets)@targets= targets
enddef write(*args)@targets.each {|t| t.write(*args)}enddef close
@targets.each(&:close)endend
Jedesmal , wenn LoggerAnrufe putsauf Ihrem MultiIOObjekt, wird es sowohl schreiben STDOUTund Ihre Log - Datei.
Bearbeiten: Ich ging voran und fand den Rest der Oberfläche heraus. Ein Protokollgerät muss auf writeund close(nicht puts) antworten . Solange MultiIOauf diese reagiert und sie auf die realen E / A-Objekte übertragen werden, sollte dies funktionieren.
Wenn Sie sich den ctor von logger ansehen, werden Sie feststellen, dass dies die Protokollrotation durcheinander bringt. def initialize(log = nil, opt = {}) @dev = @filename = @shift_age = @shift_size = nil @mutex = LogDeviceMutex.new if log.respond_to?(:write) and log.respond_to?(:close) @dev = log else @dev = open_logfile(log) @dev.sync = true @filename = log @shift_age = opt[:shift_age] || 7 @shift_size = opt[:shift_size] || 1048576 end end
JeffCharter
3
Hinweis in Ruby 2.2 @targets.each(&:close)wird abgeschrieben.
xis
Arbeitete für mich, bis mir klar wurde, dass ich regelmäßig aufrufen musste: close on log_file, um log_file zu erhalten, um zu aktualisieren, was der Logger protokolliert hatte (im Wesentlichen ein "Speichern"). STDOUT gefiel es nicht: nahe dran zu sein, die MultoIO-Idee zu besiegen. Ein Hack zum Überspringen wurde hinzugefügt: Schließen mit Ausnahme der Klasse Datei, aber ich wünschte, ich hätte eine elegantere Lösung.
Kim Miller
48
@ Davids Lösung ist sehr gut. Ich habe eine generische Delegatorklasse für mehrere Ziele basierend auf seinem Code erstellt.
require 'logger'classMultiDelegatordef initialize(*targets)@targets= targets
enddefself.delegate(*methods)
methods.each do|m|
define_method(m)do|*args|@targets.map {|t| t.send(m,*args)}endendselfendclass<<selfalias to new
endend
log_file =File.open("debug.log","a")
log =Logger.new MultiDelegator.delegate(:write,:close).to(STDOUT, log_file)
Könnten Sie bitte erklären, wie dies besser ist oder was verbesserte Dienstprogramme dieses Ansatzes sind als das einfache, das von David
Manish Sapariya am
5
Es ist die Trennung von Bedenken. MultiDelegator kann nur Anrufe an mehrere Ziele delegieren. Die Tatsache, dass ein Protokollierungsgerät eine Schreib- und eine Abschlussmethode benötigt, ist im Aufrufer implementiert. Dies macht MultiDelegator in anderen Situationen als der Protokollierung verwendbar.
Jonas054
Schöne Lösung. Ich habe versucht, damit die Ausgabe meiner Rake-Tasks in eine Protokolldatei zu übertragen. Um es mit Puts zum Laufen zu bringen (um $ stdout.puts aufrufen zu können, ohne "private Methode" Puts "aufgerufen zu bekommen), musste ich einige weitere Methoden hinzufügen: log_file = File.open (" tmp / rake.log "," a ") $ stdout = MultiDelegator.delegate (: write ,: close ,: put ,: print) .to (STDOUT, log_file) Wäre schön, wenn es möglich wäre, eine Tee-Klasse zu erstellen, von der geerbt wurde MultiDelegator, wie Sie es mit der Delegator-Klasse in stdlib tun können ...
Tyler Rick
Ich habe mir eine Delegator-ähnliche Implementierung ausgedacht, die ich DelegatorToAll genannt habe. Auf diese Weise müssen Sie nicht alle Methoden auflisten, die Sie delegieren möchten, da alle Methoden delegiert werden, die in der Delegate-Klasse (IO) definiert sind: class Tee <DelegateToAllClass (IO) end $ stdout = Tee.new (STDOUT , File.open ("# { FILE } .log", "a")) Weitere Informationen finden Sie unter gist.github.com/TylerRick/4990898 .
Tyler Rick
1
Ihre Lösung gefällt mir sehr gut, aber sie ist nicht gut als generischer Delegator, der mehrfach verwendet werden kann, da jede Delegation alle Instanzen mit neuen Methoden verschmutzt. Ich habe unten eine Antwort gepostet ( stackoverflow.com/a/36659911/123376 ), die dieses Problem behebt. Ich habe eher eine Antwort als eine Bearbeitung gepostet, da es möglicherweise lehrreich ist, den Unterschied zwischen den beiden Implementierungen zu erkennen, da ich auch Beispiele gepostet habe.
Gilt dies außerhalb von Schienen oder nur für Schienen?
Ed Sykes
Es basiert auf ActiveSupport. Wenn Sie diese Abhängigkeit bereits haben, können Sie extendjede ActiveSupport::LoggerInstanz wie oben gezeigt ausführen .
Phillipsbaker
Danke, es war hilfreich.
Lucas
Ich denke, dies ist die einfachste und effektivste Antwort, obwohl ich bei der Verwendung der config.logger.extend()Konfiguration in meiner Umgebung etwas seltsam war . Stattdessen setze ich config.loggerauf STDOUTin meinem Umfeld, erweitert dann den Logger in verschiedenen initializers.
Mattsch
14
Für diejenigen, die es einfach mögen:
log =Logger.new("| tee test.log")# note the pipe ( '|' )
log.info "hi"# will log to both STDOUT and test.log
Oder drucken Sie die Nachricht im Logger-Formatierer:
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
Ich verwende diese Technik tatsächlich, um in eine Protokolldatei, einen Cloud-Logger-Dienst (Logentries) und in einer Entwicklungsumgebung zu drucken - auch in STDOUT zu drucken.
"| tee test.log"wird die alten Ausgaben überschreiben, kann "| tee -a test.log"stattdessen sein
fangxing
13
Obwohl ich die anderen Vorschläge sehr mag, stellte ich fest, dass ich das gleiche Problem hatte, aber die Möglichkeit haben wollte, unterschiedliche Protokollierungsstufen für STDERR und die Datei zu haben.
Am Ende hatte ich eine Routing-Strategie, die auf Logger-Ebene und nicht auf E / A-Ebene multiplext, sodass jeder Logger dann auf unabhängigen Log-Ebenen arbeiten kann:
Diese Lösung gefällt mir am besten, da sie (1) einfach ist und (2) Sie dazu ermutigt, Ihre Logger-Klassen wiederzuverwenden, anstatt davon auszugehen, dass alles in eine Datei geht. In meinem Fall möchte ich mich bei STDOUT und einem GELF-Appender für Graylog anmelden. Ein MultiLoggerähnliches wie @dsz zu haben, passt sehr gut. Danke für das Teilen!
Eric Kramer
Abschnitt hinzugefügt, um Pseudovariablen (Setter / Getter) zu behandeln
Eric Kramer
11
Sie können dem Logger auch mehrere Geräteprotokollierungsfunktionen direkt hinzufügen:
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')
Hier ist eine weitere Implementierung, die von der Antwort von @ jonas054 inspiriert wurde .
Dies verwendet ein ähnliches Muster wie Delegator. Auf diese Weise müssen Sie nicht alle Methoden auflisten, die Sie delegieren möchten, da alle Methoden delegiert werden, die in einem der Zielobjekte definiert sind:
Die Antwort von @ jonas054 oben ist großartig, aber sie verschmutzt die MultiDelegatorKlasse mit jedem neuen Delegierten. Wenn Sie MultiDelegatormehrmals verwenden, werden der Klasse weiterhin Methoden hinzugefügt, was unerwünscht ist. (Siehe unten zum Beispiel)
Hier ist dieselbe Implementierung, jedoch mit anonymen Klassen, damit die Methoden die Delegatorklasse nicht verschmutzen.
classBetterMultiDelegatordefself.delegate(*methods)Class.new dodef initialize(*targets)@targets= targets
end
methods.each do|m|
define_method(m)do|*args|@targets.map {|t| t.send(m,*args)}endendclass<<selfalias to new
endend# new classend# delegateend
Hier ist ein Beispiel für die Methodenverschmutzung mit der ursprünglichen Implementierung im Gegensatz zur modifizierten Implementierung:
tee =MultiDelegator.delegate(:write).to(STDOUT)
tee.respond_to?:write
# => true
tee.respond_to?:size
# => false
Alles ist gut oben. teehat eine writeMethode, aber keine sizeMethode wie erwartet. Überlegen Sie nun, wann wir einen weiteren Delegaten erstellen:
tee2 =MultiDelegator.delegate(:size).to("bar")
tee2.respond_to?:size
# => true
tee2.respond_to?:write
# => true !!!!! Bad
tee.respond_to?:size
# => true !!!!! Bad
Oh nein, tee2reagiert sizewie erwartet, aber es reagiert auch writewegen des ersten Delegierten. Schon teejetzt reagiert sizeaufgrund der Methode Verschmutzung.
Vergleichen Sie dies mit der anonymen Klassenlösung, alles ist wie erwartet:
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
Ein Vorteil: Sie können auch verschiedene Protokollebenen für stdout und file definieren.
Ich bin zu der gleichen Idee übergegangen, "alle Methoden an Unterelemente zu delegieren", die andere Leute bereits untersucht haben, aber für jeden von ihnen den Rückgabewert des letzten Aufrufs der Methode zurückgeben. Wenn ich es nicht tat, brach es, logger-colorswas eine erwartete Integerund die Karte eine zurückgab Array.
classMultiIOdefself.delegate_all
IO.methods.each do|m|
define_method(m)do|*args|
ret =nil@targets.each {|t| ret = t.send(m,*args)}
ret
endendenddef initialize(*targets)@targets= targets
MultiIO.delegate_all
endend
Dadurch wird jede Methode auf alle Ziele neu verknüpft und nur der Rückgabewert des letzten Aufrufs zurückgegeben.
Wenn Sie Farben möchten, müssen STDOUT oder STDERR als letzte gesetzt werden, da dies die einzigen beiden Farben sind, in denen Farben ausgegeben werden sollen. Dann werden aber auch Farben in Ihre Datei ausgegeben.
logger =Logger.new MultiIO.new(File.open("log/test.log",'w'), STDOUT)
logger.error "Roses are red"
logger.unknown "Violets are blue"
Noch ein Weg. Wenn Sie die Tagged-Protokollierung verwenden und Tags auch in einer anderen Protokolldatei benötigen, können Sie dies auf diese Weise tun
# backported from rails4# config/initializers/active_support_logger.rbmoduleActiveSupportclassLogger<::Logger# Broadcasts logs to multiple loggers. Returns a module to be# `extended`'ed into other logger instances.defself.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)endend# Module.newend# broadcastdef initialize(*args)super@formatter=SimpleFormatter.new
end# Simple formatter which only displays the message.classSimpleFormatter<::Logger::Formatter# This method is invoked when a log event occursdef 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"endendend# class Loggerend# module ActiveSupport
custom_logger =ActiveSupport::Logger.new(Rails.root.join("log/alternative_#{Rails.env}.log"))Rails.logger.extend(ActiveSupport::Logger.broadcast(custom_logger))
Danach erhalten Sie UUID-Tags im alternativen Logger
["fbfea87d1d8cc101a4ff9d12461ae810"]2015-03-1216: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
Einfach, zuverlässig und funktioniert hervorragend. Vielen Dank! Beachten Sie, dass ActiveSupport::Loggermit diesem der Box funktioniert - Sie müssen nur verwenden Rails.logger.extendmit ActiveSupport::Logger.broadcast(...).
def watch(cmd)
output =StringIO.new
IO.popen(cmd)do|fd|until fd.eof?
bit = fd.getc
output << bit
$stdout.putc bit
endend
output.rewind
[output.read, $?.success?]ensure
output.close
end
result, success = watch('./my/shell_command as a String')
Hinweis Ich weiß, dass dies die Frage nicht direkt beantwortet, aber stark verwandt ist. Immer wenn ich nach einer Ausgabe für mehrere E / A gesucht habe, bin ich auf diesen Thread gestoßen. Ich hoffe, Sie finden dies auch nützlich.
def delegator(*methods)Class.new dodef initialize(*targets)@targets= targets
end
methods.each do|m|
define_method(m)do|*args|@targets.map {|t| t.send(m,*args)}endendclass<<selfaliasfor new
endend# new classend# delegate
Es hat alle die gleichen Vorteile wie sein, ohne dass der Wrapper der äußeren Klasse benötigt wird. Es ist ein nützliches Dienstprogramm in einer separaten Ruby-Datei.
Verwenden Sie es als Einzeiler, um Delegatorinstanzen wie folgt zu generieren:
Wenn Sie mit der Verwendung einverstanden sind ActiveSupport, würde ich das Auschecken sehr empfehlen. Dies ActiveSupport::Logger.broadcastist eine hervorragende und sehr präzise Möglichkeit, einem Protokollierer zusätzliche Protokollziele hinzuzufügen.
In der Tat, wenn Sie Rails verwenden 4+ (Stand dieser begehen ), brauchen Sie nicht zu tun , etwas , das gewünschte Verhalten zu bekommen - zumindest wenn Sie mit dem rails console. Wenn Sie das verwenden rails console, wird Rails automatisch so erweitert Rails.logger, dass es sowohl an das übliche Dateiziel ( log/production.logz. B.) als auch Folgendes ausgibt STDERR:
Aus unbekannten und unglücklichen Gründen ist diese Methode nicht dokumentiert. Sie können sich jedoch auf den Quellcode oder die Blog-Beiträge beziehen, um zu erfahren, wie sie funktioniert, oder Beispiele anzeigen.
Ich habe dieses Bedürfnis auch kürzlich, also habe ich eine Bibliothek implementiert, die dies tut. Ich habe gerade diese StackOverflow-Frage entdeckt und stelle sie daher allen zur Verfügung, die sie benötigen: https://github.com/agis/multi_io .
Im Vergleich zu den anderen hier genannten Lösungen ist dies ein IOeigenständiges Objekt, sodass es als Ersatz für andere reguläre E / A-Objekte (Dateien, Sockets usw.) verwendet werden kann.
Das heißt, ich habe noch nicht alle Standard-E / A-Methoden implementiert, aber diejenigen, die der E / A-Semantik folgen (z. B. #writegibt die Summe der Anzahl der Bytes zurück, die in alle zugrunde liegenden E / A-Ziele geschrieben wurden).
| tee
bevor die Datei für mich funktioniert hat, alsoLogger.new("| tee test.log")
. Beachten Sie das Rohr. Dies war aus einem Tipp auf coderwall.com/p/y_b3ra/…tee --append test.log
, um Überschreibungen zu verhindern.Antworten:
Sie können eine Pseudoklasse
IO
schreiben, die in mehrereIO
Objekte schreibt . Etwas wie:Dann legen Sie das als Ihre Protokolldatei fest:
Jedesmal , wenn
Logger
Anrufeputs
auf IhremMultiIO
Objekt, wird es sowohl schreibenSTDOUT
und Ihre Log - Datei.Bearbeiten: Ich ging voran und fand den Rest der Oberfläche heraus. Ein Protokollgerät muss auf
write
undclose
(nichtputs
) antworten . SolangeMultiIO
auf diese reagiert und sie auf die realen E / A-Objekte übertragen werden, sollte dies funktionieren.quelle
def initialize(log = nil, opt = {}) @dev = @filename = @shift_age = @shift_size = nil @mutex = LogDeviceMutex.new if log.respond_to?(:write) and log.respond_to?(:close) @dev = log else @dev = open_logfile(log) @dev.sync = true @filename = log @shift_age = opt[:shift_age] || 7 @shift_size = opt[:shift_size] || 1048576 end end
@targets.each(&:close)
wird abgeschrieben.@ Davids Lösung ist sehr gut. Ich habe eine generische Delegatorklasse für mehrere Ziele basierend auf seinem Code erstellt.
quelle
Wenn Sie sich in Rails 3 oder 4 befinden, verfügt Rails 4, wie in diesem Blogbeitrag hervorgehoben , über diese integrierte Funktionalität . So können Sie tun:
Oder wenn Sie auf Rails 3 sind, können Sie es zurückportieren:
quelle
extend
jedeActiveSupport::Logger
Instanz wie oben gezeigt ausführen .config.logger.extend()
Konfiguration in meiner Umgebung etwas seltsam war . Stattdessen setze ichconfig.logger
aufSTDOUT
in meinem Umfeld, erweitert dann den Logger in verschiedenen initializers.Für diejenigen, die es einfach mögen:
Quelle
Oder drucken Sie die Nachricht im Logger-Formatierer:
Ich verwende diese Technik tatsächlich, um in eine Protokolldatei, einen Cloud-Logger-Dienst (Logentries) und in einer Entwicklungsumgebung zu drucken - auch in STDOUT zu drucken.
quelle
"| tee test.log"
wird die alten Ausgaben überschreiben, kann"| tee -a test.log"
stattdessen seinObwohl ich die anderen Vorschläge sehr mag, stellte ich fest, dass ich das gleiche Problem hatte, aber die Möglichkeit haben wollte, unterschiedliche Protokollierungsstufen für STDERR und die Datei zu haben.
Am Ende hatte ich eine Routing-Strategie, die auf Logger-Ebene und nicht auf E / A-Ebene multiplext, sodass jeder Logger dann auf unabhängigen Log-Ebenen arbeiten kann:
quelle
MultiLogger
ähnliches wie @dsz zu haben, passt sehr gut. Danke für das Teilen!Sie können dem Logger auch mehrere Geräteprotokollierungsfunktionen direkt hinzufügen:
Zum Beispiel:
quelle
Hier ist eine weitere Implementierung, die von der Antwort von @ jonas054 inspiriert wurde .
Dies verwendet ein ähnliches Muster wie
Delegator
. Auf diese Weise müssen Sie nicht alle Methoden auflisten, die Sie delegieren möchten, da alle Methoden delegiert werden, die in einem der Zielobjekte definiert sind:Sie sollten dies auch mit Logger verwenden können.
delegate_to_all.rb ist hier verfügbar: https://gist.github.com/TylerRick/4990898
quelle
Schnell und schmutzig (siehe: https://coderwall.com/p/y_b3ra/log-to-stdout-and-a-file-at-the-same-time )
quelle
Die Antwort von @ jonas054 oben ist großartig, aber sie verschmutzt die
MultiDelegator
Klasse mit jedem neuen Delegierten. Wenn SieMultiDelegator
mehrmals verwenden, werden der Klasse weiterhin Methoden hinzugefügt, was unerwünscht ist. (Siehe unten zum Beispiel)Hier ist dieselbe Implementierung, jedoch mit anonymen Klassen, damit die Methoden die Delegatorklasse nicht verschmutzen.
Hier ist ein Beispiel für die Methodenverschmutzung mit der ursprünglichen Implementierung im Gegensatz zur modifizierten Implementierung:
Alles ist gut oben.
tee
hat einewrite
Methode, aber keinesize
Methode wie erwartet. Überlegen Sie nun, wann wir einen weiteren Delegaten erstellen:Oh nein,
tee2
reagiertsize
wie erwartet, aber es reagiert auchwrite
wegen des ersten Delegierten. Schontee
jetzt reagiertsize
aufgrund der Methode Verschmutzung.Vergleichen Sie dies mit der anonymen Klassenlösung, alles ist wie erwartet:
quelle
Sind Sie auf den Standardlogger beschränkt?
Wenn nicht, können Sie log4r verwenden :
Ein Vorteil: Sie können auch verschiedene Protokollebenen für stdout und file definieren.
quelle
Ich bin zu der gleichen Idee übergegangen, "alle Methoden an Unterelemente zu delegieren", die andere Leute bereits untersucht haben, aber für jeden von ihnen den Rückgabewert des letzten Aufrufs der Methode zurückgeben. Wenn ich es nicht tat, brach es,
logger-colors
was eine erwarteteInteger
und die Karte eine zurückgabArray
.Dadurch wird jede Methode auf alle Ziele neu verknüpft und nur der Rückgabewert des letzten Aufrufs zurückgegeben.
Wenn Sie Farben möchten, müssen STDOUT oder STDERR als letzte gesetzt werden, da dies die einzigen beiden Farben sind, in denen Farben ausgegeben werden sollen. Dann werden aber auch Farben in Ihre Datei ausgegeben.
quelle
Ich habe ein kleines RubyGem geschrieben, mit dem Sie verschiedene Dinge tun können:
Sie finden den Code auf github: teerb
quelle
Noch ein Weg. Wenn Sie die Tagged-Protokollierung verwenden und Tags auch in einer anderen Protokolldatei benötigen, können Sie dies auf diese Weise tun
Danach erhalten Sie UUID-Tags im alternativen Logger
Hoffe das hilft jemandem.
quelle
ActiveSupport::Logger
mit diesem der Box funktioniert - Sie müssen nur verwendenRails.logger.extend
mitActiveSupport::Logger.broadcast(...)
.Noch eine Option ;-)
quelle
Ich mag den MultiIO- Ansatz. Es funktioniert gut mit Ruby Logger . Wenn Sie reines E / A verwenden , funktioniert es nicht mehr, da einige Methoden fehlen, über die E / A-Objekte erwartet werden. Pipes wurden hier bereits erwähnt: Wie kann ich eine Ruby-Logger-Protokollausgabe sowohl an stdout als auch an eine Datei senden? . Hier ist, was für mich am besten funktioniert.
Hinweis Ich weiß, dass dies die Frage nicht direkt beantwortet, aber stark verwandt ist. Immer wenn ich nach einer Ausgabe für mehrere E / A gesucht habe, bin ich auf diesen Thread gestoßen. Ich hoffe, Sie finden dies auch nützlich.
quelle
Dies ist eine Vereinfachung der @ rado-Lösung.
Es hat alle die gleichen Vorteile wie sein, ohne dass der Wrapper der äußeren Klasse benötigt wird. Es ist ein nützliches Dienstprogramm in einer separaten Ruby-Datei.
Verwenden Sie es als Einzeiler, um Delegatorinstanzen wie folgt zu generieren:
ODER verwenden Sie es als Fabrik wie folgt:
quelle
Sie können
Loog::Tee
Objekt ausloog
Edelstein verwenden:Genau das, wonach Sie suchen.
quelle
Wenn Sie mit der Verwendung einverstanden sind
ActiveSupport
, würde ich das Auschecken sehr empfehlen. DiesActiveSupport::Logger.broadcast
ist eine hervorragende und sehr präzise Möglichkeit, einem Protokollierer zusätzliche Protokollziele hinzuzufügen.In der Tat, wenn Sie Rails verwenden 4+ (Stand dieser begehen ), brauchen Sie nicht zu tun , etwas , das gewünschte Verhalten zu bekommen - zumindest wenn Sie mit dem
rails console
. Wenn Sie das verwendenrails console
, wird Rails automatisch so erweitertRails.logger
, dass es sowohl an das übliche Dateiziel (log/production.log
z. B.) als auch Folgendes ausgibtSTDERR
:Aus unbekannten und unglücklichen Gründen ist diese Methode nicht dokumentiert. Sie können sich jedoch auf den Quellcode oder die Blog-Beiträge beziehen, um zu erfahren, wie sie funktioniert, oder Beispiele anzeigen.
https://www.joshmcarthur.com/til/2018/08/16/logging-to-multiple-destinations-using-activesupport-4.html hat ein weiteres Beispiel:
quelle
Ich habe dieses Bedürfnis auch kürzlich, also habe ich eine Bibliothek implementiert, die dies tut. Ich habe gerade diese StackOverflow-Frage entdeckt und stelle sie daher allen zur Verfügung, die sie benötigen: https://github.com/agis/multi_io .
Im Vergleich zu den anderen hier genannten Lösungen ist dies ein
IO
eigenständiges Objekt, sodass es als Ersatz für andere reguläre E / A-Objekte (Dateien, Sockets usw.) verwendet werden kann.Das heißt, ich habe noch nicht alle Standard-E / A-Methoden implementiert, aber diejenigen, die der E / A-Semantik folgen (z. B.
#write
gibt die Summe der Anzahl der Bytes zurück, die in alle zugrunde liegenden E / A-Ziele geschrieben wurden).quelle
Ich denke, Ihr STDOUT wird für kritische Laufzeitinformationen und Fehler verwendet.
Also benutze ich
Debug und regelmäßige Protokollierung zu protokollieren, und schrieb dann ein paar
wo ich STDOUT-Informationen sehen muss, dass meine Skripte überhaupt ausgeführt wurden!
Bah, nur meine 10 Cent :-)
quelle