Created
July 1, 2015 20:22
-
-
Save will3216/a44c9ad3a18d69abaf67 to your computer and use it in GitHub Desktop.
Log information about callbacks for the Lifecycle of a Rails 3.2.19 (Wraps state-machine callbacks as well if state-machine is being used)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is used for debugging callbacks chains, to use this code: | |
# 1. Drop this into an initializer in your rails app | |
# 2. Set the LG_FILE_PATH to the file location you want the logging to go too | |
# 3. Set MODEL_TO_DEBUG to the class you want to debug, ie: MODEL_TO_DEBUG | |
# 4. Change the print_string method to save the relevant information. It has | |
# access to any instance methods on the object presently in the callback chain | |
# Note: Not sure how compatible this is with other versions of rails/state-machine | |
# VERSIONS PATCHED | |
# State-Machine 1.1.2 | |
# Rails 3.2.19 | |
unless Rails.env.production? || Rails.env.prod? | |
# Set these values! | |
MODEL_TO_DEBUG = MyClass | |
TAG_FOR_PRINT = 'IAmTrackingObjectLifeCycle' | |
LOG_FILE_PATH = "the/path/I/want/to/log.to" | |
file = File.open(LOG_FILE_PATH, "a") | |
TRACKING_LOGGER = Logger.new(file) | |
module CallbackPrint | |
# Modify this method! (Don't change the arguments unless you change them in all the places it is called!) | |
def print_string(kind, method, result, halted=nil) | |
print_hash = { | |
tag: TAG_FOR_PRINT, | |
timestamp: Time.now.to_f, | |
callback: method, | |
kind: kind, | |
result: result.inspect, | |
#some_column_name: instance_method_to_call, | |
#example: state, | |
#my_class_uid: self.uid, | |
staged_changes: changes, | |
previous_changes: previous_changes | |
} | |
print_hash.merge!({halted: halted}) unless halted.nil? | |
TRACKING_LOGGER.info print_hash.to_json | |
result | |
end | |
end | |
MODEL_TO_DEBUG.send(:include, CallbackPrint) | |
module ActiveSupport | |
module Callbacks | |
class Callback | |
def start(key=nil, object=nil) | |
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?") | |
case @kind | |
when :before | |
<<-RUBY_EVAL | |
if !halted && #{@compiled_options} | |
# This double assignment is to prevent warnings in 1.9.3 as | |
# the `result` variable is not always used except if the | |
# terminator code refers to it. | |
if self.class.to_s == "#{MODEL_TO_DEBUG.name}" && (#{@raw_filter.class.inspect} == Symbol || #{@raw_filter.class.inspect} == String) | |
self.print_string #{@kind.inspect.inspect}, #{@raw_filter.inspect.inspect}, (result = result = #{@filter}) | |
else | |
result = result = #{@filter} | |
end | |
halted = (#{chain.config[:terminator]}) | |
if halted | |
if self.class.to_s == "#{MODEL_TO_DEBUG.name}" && (#{@raw_filter.class.inspect} == Symbol || #{@raw_filter.class.inspect} == String) | |
self.print_string(#{@kind.inspect.inspect}, #{@raw_filter.inspect.inspect}, result, halted) | |
end | |
halted_callback_hook(#{@raw_filter.inspect.inspect}) | |
end | |
end | |
RUBY_EVAL | |
when :around | |
name = "_conditional_callback_#{@kind}_#{next_id}" | |
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 | |
def #{name}(halted) | |
if #{@compiled_options} && !halted | |
#{@filter} do | |
#puts #{self.instance_variables.inject({}){|h,v| h[v] = self.instance_variable_get(v) unless [:@chain, :@klass].include?(v) || v.class == StateMachine::Machine; h}.inspect.inspect} | |
if self.class.to_s == "#{MODEL_TO_DEBUG.name}" && (#{@raw_filter.class.inspect} == Symbol || #{@raw_filter.class.inspect} == String) | |
self.print_string(#{@kind.inspect.inspect}, #{@raw_filter.inspect.inspect}, (yield self), halted) | |
else | |
yield self | |
end | |
end | |
else | |
if self.class.to_s == "#{MODEL_TO_DEBUG.name}" && (#{@raw_filter.class.inspect} == Symbol || #{@raw_filter.class.inspect} == String) | |
self.print_string(#{@kind.inspect.inspect}, #{@raw_filter.inspect.inspect}, (yield self), halted) | |
else | |
yield self | |
end | |
end | |
end | |
RUBY_EVAL | |
"#{name}(halted) do" | |
end | |
end | |
def end(key=nil, object=nil) | |
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?") | |
case @kind | |
when :after | |
<<-RUBY_EVAL | |
if #{@compiled_options} | |
if self.class.to_s == "#{MODEL_TO_DEBUG.name}" && (#{@raw_filter.class.inspect} == Symbol || #{@raw_filter.class.inspect} == String) | |
self.print_string #{@kind.inspect.inspect}, #{@raw_filter.inspect.inspect}, #{@filter}, halted | |
else | |
#{@filter} | |
end | |
end | |
RUBY_EVAL | |
when :around | |
<<-RUBY_EVAL | |
if self.class.to_s == "#{MODEL_TO_DEBUG.name}" && (#{@raw_filter.class.inspect} == Symbol || #{@raw_filter.class.inspect} == String) | |
self.print_string #{@kind.inspect.inspect}, #{@raw_filter.inspect.inspect}, value, halted | |
else | |
value | |
end | |
end | |
RUBY_EVAL | |
end | |
end | |
end | |
end | |
end | |
if MODEL_TO_DEBUG.respond_to?(:state_machine) | |
module StateMachine | |
module EvalHelpers | |
def evaluate_method(object, method, *args, &block) | |
klass = (class << object; self; end) | |
case method | |
when Symbol | |
if klass < MODEL_TO_DEBUG | |
object.send(:print_string, type.inspect, method, (object.method(method).arity == 0 ? object.send(method, &block) : object.send(method, *args, &block))) | |
else | |
object.method(method).arity == 0 ? object.send(method, &block) : object.send(method, *args, &block) | |
end | |
when Proc, Method | |
args.unshift(object) | |
arity = method.arity | |
if block_given? && Proc === method && arity != 0 | |
if [1, 2].include?(arity) | |
args = args[0, arity - 1] + [block] | |
else | |
args << block | |
end | |
else | |
args = args[0, arity] if [0, 1].include?(arity) | |
end | |
if klass < MODEL_TO_DEBUG | |
object.send(:print_string, type.inspect, method, method.call(*args, &block)) | |
else | |
method.call(*args, &block) | |
end | |
when String | |
if klass < MODEL_TO_DEBUG | |
# penis penis penis | |
object.send(:print_string, type.inspect, method, eval(method, object.instance_eval {binding}, &block)) | |
else | |
eval(method, object.instance_eval {binding}, &block) | |
end | |
else | |
raise ArgumentError, 'Methods must be a symbol denoting the method to call, a block to be invoked, or a string to be evaluated' | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment