Dans Rails, je souhaite consigner certaines informations dans un fichier journal différent et non dans le journal standard development.log ou production.log. Je souhaite effectuer cette journalisation à partir d'une classe de modèle.
Vous pouvez créer vous-même un objet Logger à partir de n'importe quel modèle. Il suffit de transmettre le nom du fichier au constructeur et d'utiliser l'objet comme d'habitude 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
Ici, j'ai utilisé un attribut de classe pour mémoriser l'enregistreur. Ainsi, il ne sera pas créé pour chaque objet utilisateur créé, mais vous n'êtes pas obligé de le faire. Rappelez-vous aussi que vous pouvez injecter le my_logger
méthode directement dans le ActiveRecord::Base
classe (ou dans une super-classe de votre propre si vous n'aimez pas trop singe patch) pour partager le code entre les modèles de votre application.
Mettre à jour
J'ai créé une gemme basée sur la solution ci-dessous, appelée multi_logger . Faites ceci dans l’initialiseur:
MultiLogger.add_logger('post')
et appeler
Rails.logger.post.error('hi')
# or call logger.post.error('hi') if it is accessible.
et vous avez terminé.
Si vous voulez le coder vous-même, voir ci-dessous:
Une solution plus complète consisterait à placer les éléments suivants dans votre lib/
ou config/initializers/
répertoire.
L'avantage est que vous pouvez configurer le formateur pour préfixer les horodatages ou la gravité des journaux automatiquement. Ceci est accessible de n’importe où dans Rails et semble plus net en utilisant le motif 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
Une option décente qui fonctionne pour moi est d’ajouter une classe assez simple à votre dossier app/models
Telle que app/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
puis dans votre contrôleur, ou à peu près partout où vous pourriez référencer la classe d'un modèle depuis votre Rails, c'est-à-dire n'importe où vous pouvez faire Post.create(:title => "Hello world", :contents => "Lorum ipsum");
ou quelque chose de similaire auquel vous pouvez vous connecter votre fichier personnalisé comme ça
MyLog.debug "Hello world"
Définissez une classe de consignateurs dans (par exemple) 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
initialiser le logger dans (par exemple) config/initializers/special_log.rb:
SpecialLog.logger = Logger.new(SpecialLog::LogFile)
SpecialLog.logger.level = 'debug' # could be debug, info, warn, error or fatal
N'importe où dans votre application, vous pouvez vous connecter avec:
SpecialLog.debug("something went wrong")
# or
SpecialLog.info("life is good")
Voici mon logger personnalisé:
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
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
Je suggérerais d'utiliser Log4r gem pour la journalisation personnalisée. Citant la description de sa page:
Log4r est une bibliothèque de journalisation complète et flexible écrite en Ruby pour utilisation dans les programmes Ruby. Elle comporte un système de journalisation hiérarchique comprenant un nombre quelconque de niveaux, des noms de niveaux personnalisés). , héritage de journal, plusieurs destinations de sortie par événement de journal, suivi de l'exécution, formatage personnalisé, sécurité des threads, configuration XML et YAML, etc.
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')
Le cadre de journalisation, avec son nom trompeusement simple, a la sophistication dont vous rêvez!
Suivez les instructions très courtes de logging-Rails pour commencer à filtrer le bruit, à recevoir des alertes et à choisir le résultat de manière fine et détaillée.
Caressez-vous dans le dos quand vous avez terminé. Journal de roulement, tous les jours. Ça vaut le coup pour ça seul.