lib/scout_rails/store.rb in scout_rails-0.0.4 vs lib/scout_rails/store.rb in scout_rails-0.0.5.debug.pre
- old
+ new
@@ -18,12 +18,14 @@
end
# Called when the last stack item completes for the current transaction to clear
# for the next run.
def reset_transaction!
+ Thread::current[:scout_stack_unbalanced] = nil
Thread::current[:scout_scope_name] = nil
@transaction_hash = Hash.new
+ @stack = Array.new
end
# Called at the start of Tracer#instrument:
# (1) Either finds an existing MetricStats object in the metric_hash or
# initialize a new one. An existing MetricStats object is present if this +metric_name+ has already been instrumented.
@@ -36,11 +38,21 @@
end
def stop_recording(sanity_check_item, options={})
item = stack.pop
stack_empty = stack.empty?
- raise "items not equal: #{item.inspect} / #{sanity_check_item.inspect}" if item != sanity_check_item
+ # unbalanced stack - if it's unbalanced, the item is popped but nothing happens.
+ if Thread::current[:scout_stack_unbalanced]
+ return
+ end
+ # unbalanced stack check - unreproducable cases have seen this occur. when it does, sets a Thread variable
+ # so we ignore further recordings. +Store#reset_transaction!+ resets this.
+ if item != sanity_check_item
+ ScoutRails::Agent.instance.logger.warn "Scope [#{Thread::current[:scout_scope_name]}] Popped off stack: #{item.inspect} Expected: #{sanity_check_item.inspect}. Aborting."
+ Thread::current[:scout_stack_unbalanced] = true
+ return
+ end
duration = Time.now - item.start_time
if last=stack.last
last.children_time += duration
end
meta = ScoutRails::MetricMeta.new(item.metric_name, :desc => options[:desc])
@@ -56,21 +68,33 @@
transaction_hash[meta] = stat
if stack_empty
aggs=aggregate_calls(transaction_hash.dup,meta)
store_sample(options[:uri],transaction_hash.dup.merge(aggs),meta,stat)
- # ugly attempt to see if deep dup is the issue
+ # deep duplicate
duplicate = aggs.dup
duplicate.each_pair do |k,v|
duplicate[k.dup] = v.dup
end
merge_data(duplicate.merge({meta.dup => stat.dup})) # aggregrates + controller
end
end
+ # Returns the top-level category names used in the +metrics+ hash.
+ def categories(metrics)
+ cats = Set.new
+ metrics.keys.each do |meta|
+ next if meta.scope.nil? # ignore controller
+ if match=meta.metric_name.match(/\A([\w|\d]+)\//)
+ cats << match[1]
+ end
+ end # metrics.each
+ cats
+ end
+
# Takes a metric_hash of calls and generates aggregates for ActiveRecord and View calls.
def aggregate_calls(metrics,parent_meta)
- categories = %w(ActiveRecord View)
+ categories = categories(metrics)
aggregates = {}
categories.each do |cat|
agg_meta=ScoutRails::MetricMeta.new("#{cat}/all")
agg_meta.scope = parent_meta.metric_name
agg_stats = ScoutRails::MetricStats.new
\ No newline at end of file