Wie logge ich etwas in Rails in einer unabhängigen Protokolldatei ein?

157

In Rails möchte ich einige Informationen in einer anderen Protokolldatei protokollieren und nicht im Standard-Entwicklungsprotokoll oder im Produktionsprotokoll. Ich möchte diese Protokollierung von einer Modellklasse aus durchführen.

Akshat
quelle

Antworten:

187

Sie können ein Logger-Objekt in jedem Modell selbst erstellen. Übergeben Sie einfach den Dateinamen an den Konstruktor und verwenden Sie das Objekt wie die üblichen Rails logger:

class User < ActiveRecord::Base
  def my_logger
    @@my_logger ||= Logger.new("#{Rails.root}/log/my.log")
  end

  def before_save
    my_logger.info("Creating user with name #{self.name}")
  end
end

Hier habe ich ein Klassenattribut verwendet, um den Logger auswendig zu lernen. Auf diese Weise wird es nicht für jedes einzelne Benutzerobjekt erstellt, das erstellt wird, aber Sie müssen dies nicht tun. Denken Sie auch daran, dass Sie die my_loggerMethode direkt in die ActiveRecord::BaseKlasse (oder in eine eigene Superklasse, wenn Sie nicht zu viel Affen-Patches möchten) einfügen können, um den Code zwischen den Modellen Ihrer App zu teilen.

Thiago Arrais
quelle
5
Wenn Sie die gesamte Standardprotokollierung für dieses bestimmte Modell ändern möchten, können Sie sie einfach verwenden User.logger = Logger.new(STDOUT)oder wo immer Sie sich anmelden möchten. Auf die gleiche Weise ActiveRecord::Base.logger = Logger.new(STDOUT)wird die gesamte Protokollierung für alle Modelle geändert.
Dave
Weiß jemand, wie man Ordner für jedes Protokoll erstellt?
Mauro Dias
2
@ Dave Ich habe Ihren Vorschlag ausprobiert und er ist fehlgeschlagen. User.logger = Logger.new(STDOUT)Die gesamte Protokollierung für alle Modelle wurde geändert. Nun, es hat sich geändertActiveRecord::Base.logger
Fetsh
@ilzoff Ja, es ist durchaus möglich, dass sich dieses Verhalten in Rails seit 3 ​​Jahren geändert hat. Danke, dass du das gerufen hast.
Dave
Vielen Dank. Hat so ziemlich das gleiche für meine Controller , indem my_loggerin application_controller.rb.
Kstratis
40

Aktualisieren

Ich habe ein Juwel basierend auf der folgenden Lösung namens multi_logger erstellt . Tun Sie dies einfach im Initialisierer:

MultiLogger.add_logger('post')

und Ruf an

Rails.logger.post.error('hi')
# or call logger.post.error('hi') if it is accessible.

und du bist fertig.

Wenn Sie es selbst codieren möchten, siehe unten:


Eine vollständigere Lösung wäre, Folgendes in Ihr lib/oder config/initializers/Verzeichnis zu legen .

Der Vorteil besteht darin, dass Sie den Formatierer so einrichten können, dass Zeitstempel oder Schweregrade automatisch in die Protokolle eingefügt werden. Dies ist von überall in Rails zugänglich und sieht mithilfe des Singleton-Musters besser aus.

# Custom Post logger
require 'singleton'
class PostLogger < Logger
  include Singleton

  def initialize
    super(Rails.root.join('log/post_error.log'))
    self.formatter = formatter()
    self
  end

  # Optional, but good for prefixing timestamps automatically
  def formatter
    Proc.new{|severity, time, progname, msg|
      formatted_severity = sprintf("%-5s",severity.to_s)
      formatted_time = time.strftime("%Y-%m-%d %H:%M:%S")
      "[#{formatted_severity} #{formatted_time} #{$$}] #{msg.to_s.strip}\n"
    }
  end

  class << self
    delegate :error, :debug, :fatal, :info, :warn, :add, :log, :to => :instance
  end
end

PostLogger.error('hi')
# [ERROR 2012-09-12 10:40:15] hi
lulalala
quelle
1
Wofür ist das #{$$}?
Daniel Costa
1
@ DanielCosta stackoverflow.com/questions/2177008/…
lulalala
37

Eine anständige Option, die für mich funktioniert, besteht darin, Ihrem app/modelsOrdner eine ziemlich einfache Klasse hinzuzufügen, zapp/models/my_log.rb

class MyLog
  def self.debug(message=nil)
    @my_log ||= Logger.new("#{Rails.root}/log/my.log")
    @my_log.debug(message) unless message.nil?
  end
end

dann in Ihrem Controller oder wirklich fast überall dort, wo Sie in Ihrer Rails-App auf die Klasse eines Modells verweisen können, dh überall dort, wo Sie dies tun können Post.create(:title => "Hello world", :contents => "Lorum ipsum");oder ähnliches, können Sie sich in Ihrer benutzerdefinierten Datei wie dieser anmelden

MyLog.debug "Hello world"
Vaughn Draughon
quelle
2
Intelligente und einfache Lösung!
Anwar
9

Definieren Sie eine Logger-Klasse in (sagen wir) app / models / special_log.rb:

class SpecialLog
  LogFile = Rails.root.join('log', 'special.log')
  class << self
    cattr_accessor :logger
    delegate :debug, :info, :warn, :error, :fatal, :to => :logger
  end
end

Initialisieren Sie den Logger in (sagen wir) config / initializers / special_log.rb:

SpecialLog.logger = Logger.new(SpecialLog::LogFile)
SpecialLog.logger.level = 'debug' # could be debug, info, warn, error or fatal

Überall in Ihrer App können Sie sich anmelden mit:

SpecialLog.debug("something went wrong")
# or
SpecialLog.info("life is good")
Les Nightingill
quelle
4

Hier ist mein benutzerdefinierter Logger:

class DebugLog
  def self.debug(message=nil)
    return unless Rails.env.development? and message.present?
    @logger ||= Logger.new(File.join(Rails.root, 'log', 'debug.log'))
    @logger.debug(message) 
  end
end
Dorian
quelle
2
class Article < ActiveRecord::Base  

      LOGFILE = File.join(RAILS_ROOT, '/log/', "article_#{RAILS_ENV}.log")  

      def validate  
        log "was validated!"  
      end   

      def log(*args)  
       args.size == 1 ? (message = args; severity = :info) : (severity, message = args)  
       Article.logger severity, "Article##{self.id}: #{message}"  
     end  

     def self.logger(severity = nil, message = nil)  
       @article_logger ||= Article.open_log  
       if !severity.nil? && !message.nil? && @article_logger.respond_to?(severity)  
         @article_logger.send severity, "[#{Time.now.to_s(:db)}] [#{severity.to_s.capitalize}] #{message}\n"  
       end  
       message or @article_logger  
     end  

     def self.open_log  
       ActiveSupport::BufferedLogger.new(LOGFILE)  
     end  

   end  
Tony
quelle
1

Ich würde vorschlagen, Log4r gem für die benutzerdefinierte Protokollierung zu verwenden. Zitat Beschreibung von seiner Seite:

Log4r ist eine umfassende und flexible Protokollierungsbibliothek, die in Ruby zur Verwendung in Ruby-Programmen geschrieben wurde. Es verfügt über ein hierarchisches Protokollierungssystem mit einer beliebigen Anzahl von Ebenen, benutzerdefinierten Ebenennamen, Logger-Vererbung, mehreren Ausgabezielen pro Protokollereignis, Ausführungsverfolgung, benutzerdefinierter Formatierung, Thread-Sicherheit, XML- und YAML-Konfiguration und mehr.

Kangur
quelle
1
class Post < ActiveRecord::Base
    def initialize(attributes)
        super(attributes)
        @logger = Logger.new("#{Rails.root}/log/post.log")
    end

    def logger
        @logger
    end

    def some_method
        logger.info('Test 1')
    end
end

ps = Post.new
ps.some_method
ps.logger.info('Test 2')
Post.new.logger.info('Test 3')
hlcs
quelle
0

Das Logging-Framework mit seinem täuschend einfachen Namen hat die Raffinesse, nach der Sie sich sehnen!

Befolgen Sie die sehr kurzen Anweisungen von Logging-Rails , um Rauschen herauszufiltern, Warnungen zu erhalten und die Ausgabe feinkörnig und auf hoher Ebene auszuwählen.

Klopfen Sie sich auf den Rücken, wenn Sie fertig sind. Täglich Holzrollen. Allein dafür lohnt es sich.

olleolleolle
quelle