class ScoutApm::Layer

Constants

BACKTRACE_CALLER_LIMIT

Attributes

allocations_start[R]
allocations_stop[R]
annotations[R]

As we go through a part of a request, instrumentation can store additional data Known Keys:

:record_count - The number of rows returned by an AR query (From notification instantiation.active_record)
:class_name   - The ActiveRecord class name (From notification instantiation.active_record)

If no annotations are ever set, this will return nil

backtrace[RW]

If this layer took longer than a fixed amount of time, store the backtrace of where it occurred.

desc[R]

The description of this layer. Will contain additional details specific to the type of layer. For an ActiveRecord metric, it will contain the SQL run For an outoing HTTP call, it will contain the remote URL accessed Leave blank if there is nothing to note

file_name[RW]

The file name associated with the layer. Only used for autoinstruments overhead logging.

name[RW]

Name: a more specific name of this single item

Examples: "Rack::Cache", "User#find", "users/index", "users/index.html.erb"

Accessor, so we can update a layer if multiple pieces of instrumentation work

together at different layers to fill in the full data. See the ActiveRecord
instrumentation for an example of how this is useful
start_time[R]

Time objects recording the start & stop times of this layer

stop_time[R]

Time objects recording the start & stop times of this layer

type[R]

Type: a general name for the kind of thing being tracked.

Examples: "Middleware", "ActiveRecord", "Controller", "View"

Public Class Methods

new(type, name, start_time = Time.now) click to toggle source
# File lib/scout_apm/layer.rb, line 56
def initialize(type, name, start_time = Time.now)
  @type = type
  @name = name
  @start_time = start_time
  @allocations_start = ScoutApm::Instruments::Allocations.count
  @allocations_stop = 0

  # initialize these only on first use
  @children = nil
  @annotations = nil
  @desc = nil
end

Public Instance Methods

add_child(child) click to toggle source
# File lib/scout_apm/layer.rb, line 73
def add_child(child)
  @children ||= LayerChildrenSet.new
  @children << child
end
annotate_layer(hsh) click to toggle source

This data is internal to ScoutApm, to add custom information, use the Context api.

# File lib/scout_apm/layer.rb, line 92
def annotate_layer(hsh)
  @annotations ||= {}
  @annotations.merge!(hsh)
end
caller_array() click to toggle source

In Ruby 2.0+, we can pass the range directly to the caller to reduce the memory footprint.

# File lib/scout_apm/layer.rb, line 117
def caller_array
  # omits the first several callers which are in the ScoutAPM stack.
  if ScoutApm::Agent.instance.context.environment.ruby_2? || ScoutApm::Agent.instance.context.environment.ruby_3? 
    caller(3...BACKTRACE_CALLER_LIMIT)
  else
    caller[3...BACKTRACE_CALLER_LIMIT]
  end
end
capture_backtrace!() click to toggle source
# File lib/scout_apm/layer.rb, line 112
def capture_backtrace!
  @backtrace = caller_array
end
children() click to toggle source

An array of children layers For instance, if we are in a middleware, there will likely be only a single child, which is another middleware. In a Controller, we may have a handful of children: [ActiveRecord, ActiveRecord, View, HTTP Call].

This useful to get actual time spent in this layer vs. children time

TODO: Check callers for compatibility w/ nil to avoid making an empty array

# File lib/scout_apm/layer.rb, line 24
def children
  @children || LayerChildrenSet.new
end
desc=(desc) click to toggle source
# File lib/scout_apm/layer.rb, line 87
def desc=(desc)
  @desc = desc
end
legacy_metric_name() click to toggle source

This is the old style name. This function is used for now, but should be removed, and the new type & name split should be enforced through the app.

# File lib/scout_apm/layer.rb, line 108
def legacy_metric_name
  "#{type}/#{name}"
end
limited?() click to toggle source
# File lib/scout_apm/layer.rb, line 69
def limited?
  false
end
record_allocations!() click to toggle source

Fetch the current number of allocated objects. This will always increment - we fetch when initializing and when stopping the layer.

# File lib/scout_apm/layer.rb, line 83
def record_allocations!
  @allocations_stop = ScoutApm::Instruments::Allocations.count
end
record_stop_time!(stop_time = Time.now) click to toggle source
# File lib/scout_apm/layer.rb, line 78
def record_stop_time!(stop_time = Time.now)
  @stop_time = stop_time
end
subscopable!() click to toggle source
# File lib/scout_apm/layer.rb, line 97
def subscopable!
  @subscopable = true
end
subscopable?() click to toggle source
# File lib/scout_apm/layer.rb, line 101
def subscopable?
  @subscopable
end
to_s() click to toggle source

May not be safe to call in every rails app, relies on Time#iso8601

# File lib/scout_apm/layer.rb, line 131
def to_s
  name_clause = "#{type}/#{name}"

  total_string = total_call_time == 0 ? nil : "Total: #{total_call_time}"
  self_string = total_exclusive_time == 0 ? nil : "Self: #{total_exclusive_time}"
  timing_string = [total_string, self_string].compact.join(", ")

  time_clause = "(Start: #{start_time.iso8601} / Stop: #{stop_time.try(:iso8601)} [#{timing_string}])"
  desc_clause = "Description: #{desc.inspect}"
  children_clause = "Children: #{children.length}"

  "<Layer: #{name_clause} #{time_clause} #{desc_clause} #{children_clause}>"
end
total_allocations() click to toggle source

These are almost identical to the timing metrics.

# File lib/scout_apm/layer.rb, line 174
def total_allocations
  if @allocations_stop > 0
    allocations = (@allocations_stop - @allocations_start)
  else
    allocations = (ScoutApm::Instruments::Allocations.count - @allocations_start)
  end
  allocations < 0 ? 0 : allocations
end
total_call_time() click to toggle source

Time Calculations

# File lib/scout_apm/layer.rb, line 149
def total_call_time
  if stop_time
    stop_time - start_time
  else
    Time.now - start_time
  end
end
total_exclusive_allocations() click to toggle source
# File lib/scout_apm/layer.rb, line 183
def total_exclusive_allocations
  total_allocations - child_allocations
end
total_exclusive_time() click to toggle source
# File lib/scout_apm/layer.rb, line 157
def total_exclusive_time
  total_call_time - child_time
end

Private Instance Methods

child_allocations() click to toggle source
# File lib/scout_apm/layer.rb, line 187
def child_allocations
  children.
    map { |child| child.total_allocations }.
    inject(0) { |sum, obj| sum + obj }
end
child_time() click to toggle source
# File lib/scout_apm/layer.rb, line 161
def child_time
  children.
    map { |child| child.total_call_time }.
    inject(0) { |sum, time| sum + time }
end