Wenn das Monitoring anspringt und sich beschwert, dass bei einem Server der Speicherplatz knapp wird, geht bei vielen erfahrenen Admins der erste Blick in Richtung Logs. Bei der Entwicklung loggt man lieber ein paar Informationen mehr als weniger, man könnte es ja nochmal brauchen. Und den Routinetask, die ganz alten Logs aufzuräumen, den erledigen wir im stressigen Alltag morgen. Bestimmt morgen. Und dann läuft die App einige Zeit, die Logs füllen sich, und irgendwann wird’s eng.
Für solche Fälle gibt es Log Rotation. Wenn die Logdatei eine bestimmte Größe und/oder ein bestimmtes Alter erreicht, werden die früheren Einträge ausgelagert oder gleich gelöscht, je nach Einstellungen. Beispielsweise kann eine Strategie so aussehen: “Starte für jeden Tag ein neues Logfile, bewahre die letzten 14 Tage an Logfiles auf, entferne alles ältere”.
Eine Möglichkeit, so etwas umzusetzen, ist das Tool logrotate, das bei vielen Servern zur Standardausstattung gehört. Ruby on Rails kann etwas ganz ähnliches aber auch selbst.
Die Basis dafür ist die Ruby-Klasse Logger:
require 'logger'
my_logger = Logger.new('events.log', 3, 10485760)
my_logger.add(Logger::INFO, 'Log this info message')
In diesem Fall landen die Logeinträge zunächst in der Datei events.log. Wenn diese Datei eine Größe von 10 MB (10 × 1024 × 1024 = 10485760 Bytes) erreicht hat, werden die älteren Beiträge in events.log.0 gepackt, und eine neue events.log begonnen. Wenn diese ebenfalls das Größenlimit erreicht hat, wird die bisherige events.log.0 zu events.log.1, events.log wird zur neuen events.log.0 und es gibt erneut eine neue events.log. Aufgehoben werden, siehe den zweiten Parameter in Logger.new, maximal drei Dateien. Also wird bei der nächsten Rotation aus dem bisherigen events.log.1 nicht events.log.2, sondern die ganz alten Einträge werden entfernt.
Neben einer Beschränkung nach Dateigröße kann man auch nach Zeit rotieren:
require 'logger'
logger = Logger.new('events.log', 'weekly')
my_logger.add(Logger::INFO, 'Log this info message')
In diesem Beispiel wird jede Woche, genauer jeden Sonntag, ein neues Logfile gestartet. In dieser Variante gibt es keine maximale Zahl an Dateien, die aufgehoben werden. Man muss also noch anderweitig darauf achten, dass nicht Hunderte “Wochen-Files” die Festplatte verstopfen. Neben weekly kann man auch daily oder monthly verwenden.
Und ganz aktuell, ab dem kommenden Rails 4.0, werden neben Strings auch Symbole unterstützt. Dann wird auch etwas wie Logger.new('events.Log', :weekly) möglich sein. Wer diese Variante bereits jetzt verwenden möchte, kann die bereits veröffentlichte Version 1.7.0 des Gems logger nutzen.
In Ruby on Rails kann man die Logger-Klasse einfach in der Konfiguration des gewünschten Environments einbauen. Um beispielsweise die Logs für production wöchentlich zu rotieren, setzt man in config/environments/production.rb einfach
config.logger = Logger.new(config.paths["log"].first, "weekly")
Auch in Kombination mit ActiveSupport::TaggedLogging ist das Setup nicht viel komplizierter:
config.logger = ActiveSupport::TaggedLogging.new(
Logger.new(config.paths["log"].first, "weekly")
)
Diese Möglichkeiten erlauben es - anstelle von oder in Kombination mit Tools außerhalb von Rails - den Wildwuchs bei Logfiles unter Kontrolle zu bringen.