Skip to content

Instantly share code, notes, and snippets.

@terrbear
Created February 6, 2012 22:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save terrbear/1755329 to your computer and use it in GitHub Desktop.
Save terrbear/1755329 to your computer and use it in GitHub Desktop.
class DbLog < ActiveRecord::Base
belongs_to :loggable, :polymorphic => true
module Loggable
extend ActiveSupport::Concern
included do
has_many :db_logs, :foreign_key => "loggable_id" if self.respond_to?(:has_many)
end
def log_name
DbLog.silence! do
"#{self.class.name}:#{self.id}:#{Date.today}"
end
end
def log
DbLog.silence! do
@dblog ||= DbLog.find_or_create_by_name(self.log_name)
end
end
module ClassMethods
def unloggable(method_name)
#[terry] don't overwrite methods that are = or ? or dblog'd already or are id
#puts "checking method_name: #{method_name}"
method_defined?("#{method_name}_with_dblog") ||
method_name =~ /dblog/ ||
method_name =~ /db_log/ ||
%w(log_name log).include?(method_name) ||
method_name =~ /=|\?/ ||
method_name =~ /callback/ ||
method_name == 'id' ||
(respond_to?(:reflect_on_all_associations) && self.reflect_on_all_associations.map(&:name).include?(method_name.to_sym))
end
def method_added(name)
return if unloggable(name.to_s)
#puts "ACM'ing #{name}"
define_method "#{name}_with_dblog" do |*args|
DbLog.log(self) do
send("#{name}_without_dblog", *args)
end
end
alias_method_chain name, :dblog
end
end
end
def log
self.content
end
def flush
self.class.unregister(self)
self.save!
end
def write(message)
self.content ||= ""
self.content << "\n#{message}"
end
#[terry] taken from http://rails.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html bc we need
#to support STI.
def loggable_type=(stype)
super(stype.to_s.classify.constantize.base_class.to_s)
end
class << self
def listeners=(set)
@listeners = set
end
def listeners
@listeners ||= Set.new
end
def register(log)
listeners << log
end
def unregister(log)
listeners.delete(log)
end
def silence!
begin
old_listeners, listeners = listeners, Set.new
yield
ensure
listeners = old_listeners
end
end
def write(message)
listeners.each do |listener|
listener.write(message)
end
message
end
def flush
listeners.each do |listener|
listener.flush
end
end
def log(scope, &block)
if scope.respond_to?(:db_logs)
log = scope.db_logs.build(:name => scope.log_name)
else
name = scope.respond_to?(:log_name) ? scope.log_name : scope.to_s
log = DbLog.find_or_create_by_name(name)
end
begin
DbLog.register(log)
return yield
ensure
log.flush
end
end
end
end
# == Schema Information
#
# Table name: db_logs
#
# id :integer(4) not null, primary key
# content :text
# loggable_type :string(255)
# loggable_id :integer(4)
# created_at :datetime
# updated_at :datetime
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment