- Übersicht
- Coding-Beispiele
- Formatter
- Weitere Hinweise
Ü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
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 => "test_log4r_file.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 2b: Logger in Datei/Anhängen
Per Standard wird die Log-Datei jeweils neu erstellt, bisherige Log-Daten werden überschrieben.
Mit der Option :trunc ⇒ false werden neue Log-Daten an ein existierendes Logfile angehängt.
require 'rubygems' require 'log4r' include Log4r log = Logger.new('my_log') log.outputters = FileOutputter.new('log_warn', :filename => "test_log4r_file_trunc_false.log", :level => WARN, :trunc => false #log info attached ) log.add(FileOutputter.new('log_warn', :filename => "test_log4r_file_trunc_true.log", :level => WARN, :trunc => true )) 1.upto(100){|i| log.warn("Warning number #{i}") }
Korrektur: Der Default-Wert der trunc-Option ist Versionsabhängig.
- Version 1.0.5: true (immer neues Logfile)
- Version 1.1.8: false (Log wird erweitert, neue Einträge werden agehängt).
Beispiel 2c: Logger in Datei mit max. Größe und Alter
Eine Unterklasse von FileOutputter erlaubt die Begrenzung auf eine maximale Dateigröße und Alter einer Log-Datei.
Bei erreichen der Grenze (max. Größe in Byte oder Alter in Sekunden) wird die Log-Datei geschlossen und eine neue angelegt. Die jeweiligen Log-Dateien sind durchnummeriert.
require 'rubygems' require 'log4r' include Log4r log = Logger.new('my_log') log.outputters = FileOutputter.new('log_warn', :filename => "test_log4r_file_rollingfile.log", :level => WARN ) log.add(RollingFileOutputter.new('log_warn', :filename => "test_log4r_file_rollingfile_maxsize.log", :level => WARN, :maxsize => 1024 #Maximum size of the file in bytes )) log.add(RollingFileOutputter.new('log_warn', :filename => "test_log4r_file_rollingfile_trunc.log", :level => WARN, :maxtime => 42 #Maximum age of the file in seconds )) 1.upto(100){|i| log.warn("Warning number #{i}") }
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 => "test_log4r_multi_warn.log", :level => WARN ) ) log.add(FileOutputter.new('log_info', :filename => "test_log4r_multi_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...")
Hinweise:
- Alte Log-Dateien werden überschrieben.
- Die Option :trunc ⇒ false bewirkt ein Anhängen neuer Log-Informationen.
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?
Ausgabe des Loggers mit Trace
WARN my_log(test_log4r_trace.rb:10): you better be prepared ERROR my_log(test_log4r_trace.rb:11): now you are in trouble FATAL my_log(test_log4r_trace.rb:12): this is the end...
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.
Beispiel 6: 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)
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/c:/program files/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'/c:/program files/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'/log4r.wiki.rb:13) 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/c:/program files/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'/c:/program files/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'/log4r.wiki.rb:13) 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/c:/program files/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'/c:/program files/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'/log4r.wiki.rb:13)
Weitere Hinweise
Logger-Ebenen
Es ist möglich verschiedene eigene Levels anzugeben. Die verschiedenen Levels werden dynamisch generiert.
Ein Seiteneffekt davon ist, das Log4r::INFO u.Co. erst nach dem erzeugen des Loggers zur Verfügung stehen.
Werden die Konstanten vorab benötigt, kann man sie selbst erzeugen mit:
Log4r.define_levels(*Log4r::Log4rConfig::LogLevels) #Generieren Log4r::INFO u.Co.
Loglevels-Konstanten
Verwendet man Log4r::INFO und bekommt man die Fehlermeldung, das die Konstante nicht definiert ist:
Es muss erst ein Logger definiert sein. Die Konstanten werden dynamisch generiert.
Weblinks
- http://entwickler.de/zonen/portale/psecom,id,101,online,1092,p,0.html Rubys leistungsfähigste Logging-Bibliothek log4r (Markus Jais)
- http://angrez.blogspot.com/2006/12/log4r-usage-and-examples.html Englisch, nicht ganz so geschwätzig wie dieses Dokument ;-)