class ScoutApm::AutoInstrument::Rails::Rewriter
Public Class Methods
new()
click to toggle source
Calls superclass method
# File lib/scout_apm/auto_instrument/rails.rb, line 50 def initialize super # Keeps track of the parent - child relationship between nodes: @nesting = [] # The stack of method nodes (type :def): @method = [] # The stack of class nodes: @scope = [] @cache = Cache.new end
Public Instance Methods
instrument(source, file_name, line)
click to toggle source
# File lib/scout_apm/auto_instrument/rails.rb, line 65 def instrument(source, file_name, line) # Don't log huge chunks of code... just the first line: if lines = source.lines and lines.count > 1 source = lines.first.chomp + "..." end method_name = @method.last.children[0] bt = ["#{file_name}:#{line}:in `#{method_name}'"] return [ "::ScoutApm::AutoInstrument("+ source.dump + ",#{bt}){", "}" ] end
on_and_asgn(node)
click to toggle source
# File lib/scout_apm/auto_instrument/rails.rb, line 112 def on_and_asgn(node) process(node.children[1]) end
on_block(node)
click to toggle source
# File lib/scout_apm/auto_instrument/rails.rb, line 87 def on_block(node) # If we are not in a method, don't do any instrumentation: return if @method.empty? line = node.location.line || 'line?' column = node.location.column || 'column?' # not used method_name = node.children[0].children[1] || '*unknown*' # not used file_name = @source_rewriter.source_buffer.name wrap(node.location.expression, *instrument(node.location.expression.source, file_name, line)) end
on_mlhs(node)
click to toggle source
# File lib/scout_apm/auto_instrument/rails.rb, line 99 def on_mlhs(node) # Ignore / don't instrument multiple assignment (LHS). return end
on_op_asgn(node)
click to toggle source
# File lib/scout_apm/auto_instrument/rails.rb, line 104 def on_op_asgn(node) process(node.children[2]) end
on_or_asgn(node)
click to toggle source
# File lib/scout_apm/auto_instrument/rails.rb, line 108 def on_or_asgn(node) process(node.children[1]) end
on_send(node)
click to toggle source
Handle the method call AST node. If this method doesn't call `super`, no futher rewriting is applied to children.
Calls superclass method
# File lib/scout_apm/auto_instrument/rails.rb, line 117 def on_send(node) # We aren't interested in top level function calls: return if @method.empty? if @cache.local_assignments?(node) return super end # This ignores both initial block method invocation `*x*{}`, and subsequent nested invocations `x{*y*}`: return if parent_type?(:block) # Extract useful metadata for instrumentation: line = node.location.line || 'line?' column = node.location.column || 'column?' # not used method_name = node.children[1] || '*unknown*' # not used file_name = @source_rewriter.source_buffer.name # Wrap the expression with instrumentation: wrap(node.location.expression, *instrument(node.location.expression.source, file_name, line)) end
parent_type?(type, up = 1)
click to toggle source
Look up 1 or more nodes to check if the parent exists and matches the given type. @param type [Symbol] the symbol type to match. @param up [Integer] how far up to look.
# File lib/scout_apm/auto_instrument/rails.rb, line 83 def parent_type?(type, up = 1) parent = @nesting[@nesting.size - up - 1] and parent.type == type end
process(node)
click to toggle source
Invoked for every AST node as it is processed top to bottom.
Calls superclass method
# File lib/scout_apm/auto_instrument/rails.rb, line 149 def process(node) # We are nesting inside this node: @nesting.push(node) if node and node.type == :def # If the node is a method, push it on the method stack as well: @method.push(node) super @method.pop elsif node and node.type == :class @scope.push(node.children[0]) super @scope.pop else super end @nesting.pop end