Übersicht
| Mehrfache Ausgabe | √ |
| Mehrfache Ausgabe mit unterschiedlichem Level | √ |
| Eigene Level möglich | √ |
| Abfrage auf Level möglich? | √ |
| Format definierbar | √ |
| Tracing möglich? | √ |
| Verhalten bei Logfiles | overwrite |
| URL des Rubyforge-Projekts | log4r |
Ausgabeziele:
- STDOUT
- STDERR
- File
- Weitere definierbar
Vorhandene Level:
- fatal
- error
- warn
- info
- debug
Weitere URLS:
Weitere Möglichkeiten:
- Konfiguration als XML und YAML möglich
- Remotelogging möglich
Anmerkungen
- Alte Log-Dateien werden überschrieben.
Coding-Beispiele
Beispiel 1: Logger auf STDOUT
require 'rubygems'
require 'log4r'
include Log4r
log = Logger.new('my_log')
log.outputters = StdoutOutputter.new('log_stdout', :level => WARN )
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
Ausgabe des Loggers log_stdout
WARN my_log: you better be prepared
ERROR my_log: now you are in trouble
FATAL my_log: this is the end...
Beispiel 2: Logger in Datei
require 'rubygems'
require 'log4r'
include Log4r
log = Logger.new('my_log')
log.outputters = FileOutputter.new('log_warn', :filename => "test2_warn.log", :level => WARN )
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
Ausgabe des Loggers log_warn (File)
WARN my_log: you better be prepared ERROR my_log: now you are in trouble FATAL my_log: this is the end...
Beispiel 3: Mehrere gleichzeitige Loggerausgaben
Die mehrfache Ausgabe eines Logs kann sinnvoll sein. Fehler (ERROR und FATAL) werden beim Programmablauf ausgegeben (STDOUT), gleichzeitig werden in einer Datei zusätzlich die Warnungen, Informationen und Debughinweise gespeichert.
require 'rubygems'
require 'log4r'
include Log4r
log = Logger.new('my_log')
log.outputters = StdoutOutputter.new('log_stdout', :level => ERROR )
log.add(FileOutputter.new('log_warn', :filename => "test3_warn.log", :level => WARN ) )
log.add(FileOutputter.new('log_info', :filename => "test3_info.log", :level => INFO) )
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
Ausgabe des Loggers log_stdout
ERROR my_log: now you are in trouble
FATAL my_log: this is the end...
Ausgabe des Loggers log_warn (File)
WARN my_log: you better be prepared ERROR my_log: now you are in trouble FATAL my_log: this is the end...
Ausgabe des Loggers log_info (File)
INFO my_log: important information WARN my_log: you better be prepared ERROR my_log: now you are in trouble FATAL my_log: this is the end...
Beispiel 4: Logger mit Trace-Information
Was nützt ein Log-File, wenn man anschliessend nicht weiß, woher das Problem stammt? Die Lösung: Ausgeben, wo die log-Information ermittelt wird
require 'rubygems'
require 'log4r'
include Log4r
log = Logger.new('my_log')
log.trace = true
log.outputters = StdoutOutputter.new('log_stdout', :level => WARN )
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
Beispiel 5: Logger mit Level
Die Ausgabe des Loggers erfordert evtl. viel Aufwand (=Rechenzeit). Man denke blos an komplexe Strukturen, die im Logger protokolliert werden sollen.
Zur Einsparung von Laufzeit bietet es sich an, den Logger nur dann zu rufen, wenn das entsprechende Level überhaupt verwendet wird.
require 'rubygems'
require 'log4r'
include Log4r
log = Logger.new('my_log')
log.level = ERROR
log.outputters = StdoutOutputter.new('log_stdout', :level => WARN )
puts "log.debug?: #{log.debug?}"
puts "log.info?: #{log.info?}"
puts "log.warn?: #{log.warn?}"
puts "log.error?: #{log.error?}"
puts "log.fatal?: #{log.fatal?}"
log.debug("just a debug message") if log.debug?
log.info("important information") if log.info?
log.warn("you better be prepared") if log.warn?
log.warn("a warning without a 'if' afterwords")
log.error("now you are in trouble") if log.error?
log.fatal("this is the end...") if log.fatal?
Beispiel 5: Tempfile
Bei Bedarf kann die Ausgabe auch in temporäre Dateien umgeleitet werden.
require 'rubygems'
require 'log4r'
include Log4r
require 'tempfile'
logfile = Tempfile.new("xxx_warn.log")
log = Logger.new('my_log')
log.outputters = Log4r::IOOutputter.new('log_xxx', logfile, :level => WARN )
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
logfile.close()
logfile.open()
puts logfile.readlines()
logfile.close(true)
Ausgabe des Loggers mit level
ERROR my_log: now you are in trouble
FATAL my_log: this is the end...
log.debug?: false
log.info?: false
log.warn?: false
log.error?: true
log.fatal?: true
ERROR my_log: now you are in trouble
FATAL my_log: this is the end...
Anmerkungen:
- level= setzt das Level des Loggers
- level? ermöglicht die Abfrage, ob das gewünschte Level verwendet wird.
- Das Level des Loggers hat eine höhere Priorität als die des Outputers. D.h. wenn der Logger ein Level ignoriert, kann es der Outputer auch nicht ausgeben.
Formatter
Mit Hilfe von Formatters ist es möglich, die Ausgabe des Loggers anzupassen.
Beispiel: Simple Formatter
require 'rubygems'
require 'log4r'
include Log4r
log = Logger.new('my_log')
log.trace = true
log.outputters = FileOutputter.new('log_format',
:filename => 'test_log4r_formatter_simple.log',
:level => WARN,
:formatter => Log4r::SimpleFormatter
)
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
Ein Trace wird nicht unterstützt!
Ausgabe des Loggers mit allen trace-Ebenen
WARN my_log> you better be prepared ERROR my_log> now you are in trouble FATAL my_log> this is the end...
Beispiel: Basic Formatter
Der Basic-Formatter ist zugleich der Default-Formatter.
require 'rubygems'
require 'log4r'
include Log4r
log = Logger.new('my_log')
log.trace = true
log.outputters = FileOutputter.new('log_format',
:filename => 'test_log4r_formatter_basic.log',
:level => WARN,
:formatter => Log4r::BasicFormatter
)
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
Ausgabe des Loggers mit allen trace-Ebenen
WARN my_log(test_log4r_formatter_basic.rb:14): you better be prepared ERROR my_log(test_log4r_formatter_basic.rb:15): now you are in trouble FATAL my_log(test_log4r_formatter_basic.rb:16): this is the end...
Beispiel: Änderung des Formatters
Je nach Anwendung liegt ein Fehler nicht an der Stelle, an der das Problem auftritt, sondern an einem Aufruf vorher. Da kann es sinnvoll sein, den kompletten Aufrufpfad zu nutzen.
Zur Realisierung bietet es sich an, einen eigenen Formatter zu definieren.
require 'rubygems'
require 'log4r'
include Log4r
class Log4r::LevelFormatter < Log4r::BasicFormatter
#Use another log-format with the complete trace path
def format(event)
buff = sprintf(@@basicformat, MaxLevelLength, LNAMES[event.level],
event.name)
#~ buff += (event.tracer.nil? ? "" : "(#{event.tracer[2]})") + ": "
buff += ": "
buff += format_object(event.data)
buff += (event.tracer.nil? ? "" : " (#{event.tracer.join('/')})")
buff += "\n"
buff
end
end
def test()
log = Logger.new('my_log')
log.trace = true
log.outputters = FileOutputter.new('log_format',
:filename => 'test_log4r_formatter.log',
:level => WARN,
:formatter => Log4r::LevelFormatter
)
log.debug("just a debug message")
log.info("important information")
log.warn("you better be prepared")
log.error("now you are in trouble")
log.fatal("this is the end...")
end
def test2()
test
end
def test3()
test2
end
test3
Ausgabe des Loggers mit allen trace-Ebenen
WARN my_log: you better be prepared (test_log4r_formatter.rb:30:in `test'/test_log4r_formatter.rb:36:in `test2'/test_log4r_formatter.rb:40:in `test3'/test_log4r_formatter.rb:43) ERROR my_log: now you are in trouble (test_log4r_formatter.rb:31:in `test'/test_log4r_formatter.rb:36:in `test2'/test_log4r_formatter.rb:40:in `test3'/test_log4r_formatter.rb:43) FATAL my_log: this is the end... (test_log4r_formatter.rb:32:in `test'/test_log4r_formatter.rb:36:in `test2'/test_log4r_formatter.rb:40:in `test3'/test_log4r_formatter.rb:43)