Como registrar algo no Rails em um arquivo de log independente?

157

No Rails, quero registrar algumas informações em um arquivo de log diferente e não no padrão development.log ou production.log. Eu quero fazer esse log de uma classe de modelo.

akshat
fonte

Respostas:

187

Você pode criar um objeto Logger de dentro de qualquer modelo. Apenas passe o nome do arquivo para o construtor e use o objeto como o Rails usual 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

Aqui eu usei um atributo de classe para memorizar o criador de logs. Dessa forma, ele não será criado para cada objeto Usuário criado, mas você não é obrigado a fazer isso. Lembre-se também de que você pode injetar o my_loggermétodo diretamente na ActiveRecord::Baseclasse (ou em alguma superclasse de sua preferência, se você não gostar muito do patch do macaco) para compartilhar o código entre os modelos do seu aplicativo.

Thiago Arrais
fonte
5
Se você deseja alterar todo o log padrão para esse modelo específico, você pode simplesmente usar User.logger = Logger.new(STDOUT)ou onde quer que você faça o logon. Da mesma forma, ActiveRecord::Base.logger = Logger.new(STDOUT)alterará todo o log para todos os modelos.
31511 Dave
Alguém sabe como criar pastas para cada log?
Mauro Dias
2
@ Dave Tentei sua sugestão e falhou. User.logger = Logger.new(STDOUT)mudou todo o log para todos os modelos. Bem, isso mudouActiveRecord::Base.logger
fetsh
@ilzoff Sim, é bem possível que esse comportamento tenha mudado no Rails desde 3 anos atrás. Obrigado por chamar isso.
Dave
Obrigado. Fez praticamente o mesmo para os meus controladores, colocando my_loggerem application_controller.rb.
Kratis #
40

Atualizar

Fiz uma gema com base na solução abaixo, chamada multi_logger . Basta fazer isso no inicializador:

MultiLogger.add_logger('post')

e ligar

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

e você terminou.

Se você deseja codificá-lo, veja abaixo:


Uma solução mais completa seria colocar o seguinte no seu diretório lib/ou config/initializers/.

O benefício é que você pode configurar o formatador para prefixar timestamps ou severity nos logs automaticamente. Isso pode ser acessado de qualquer lugar no Rails e fica mais limpo usando o padrão singleton.

# 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
fonte
1
Para que serve #{$$}?
Daniel Costa
1
@DanielCosta stackoverflow.com/questions/2177008/…
lulalala 19/18
37

Uma opção decente que funciona para mim é apenas adicionar uma classe bastante simples à sua app/modelspasta, comoapp/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

no controlador, ou quase em qualquer lugar em que você possa referenciar a classe de um modelo a partir do aplicativo rails, ou seja, em qualquer lugar que você possa fazer Post.create(:title => "Hello world", :contents => "Lorum ipsum");ou algo semelhante, você poderá fazer logon no seu arquivo personalizado como este

MyLog.debug "Hello world"
Vaughn Draughon
fonte
2
Solução inteligente e simples!
Anwar
9

Defina uma classe de criador de logs em (digamos) 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

inicialize o logger (digamos) config / initializers / special_log.rb:

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

Em qualquer lugar do seu aplicativo, você pode fazer login com:

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

Aqui está o meu criador de logs personalizado:

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
fonte
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
fonte
1

Eu sugeriria o uso do Log4r gem para log personalizado. Citando a descrição de sua página:

O Log4r é uma biblioteca de registro abrangente e flexível, escrita em Ruby para uso em programas Ruby. Possui um sistema de registro hierárquico de qualquer número de níveis, nomes de níveis personalizados, herança do criador de log, vários destinos de saída por evento de log, rastreamento de execução, formatação personalizada, segurança de encadeamento, configuração XML e YAML e muito mais.

Kangur
fonte
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
fonte
0

A estrutura de log, com seu nome enganosamente simples, tem a sofisticação que você deseja!

Siga as instruções muito curtas dos trilhos de registro para começar a filtrar o ruído, receber alertas e escolher a saída de maneira refinada e de alto nível.

Dê um tapinha nas costas quando terminar. Rolando log, diariamente. Vale a pena só por isso.

olleolleolle
fonte