class Skylight::Core::Instrumenter

@api private

Constants

KEY
TOO_MANY_UNIQUES

Attributes

config[R]
gc[R]
uuid[R]

Public Class Methods

match?(string, regex) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 202
def self.match?(string, regex)
  @scanner ||= StringScanner.new("")
  @scanner.string = string
  @scanner.match?(regex)
end
native_new(_uuid, _config_env) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 45
def self.native_new(_uuid, _config_env)
  raise "not implemented"
end
new(config) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 49
def self.new(config)
  config.validate!

  uuid = SecureRandom.uuid
  inst = native_new(uuid, config.to_native_env)
  inst.send(:initialize, uuid, config)
  inst
end
new(uuid, config) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 58
def initialize(uuid, config)
  @uuid = uuid
  @gc = config.gc
  @config = config
  @subscriber = Subscriber.new(config, self)

  key = "#{KEY}_#{self.class.trace_class.name}".gsub(/\W/, "_")
  @trace_info = @config[:trace_info] || TraceInfo.new(key)
  @mutex = Mutex.new
end
trace_class() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 41
def self.trace_class
  Trace
end

Public Instance Methods

broken!() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 258
def broken!
  return unless (trace = @trace_info.current)
  trace.broken!
end
check_install!() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 98
def check_install!
  true
end
current_trace() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 89
def current_trace
  @trace_info.current
end
current_trace=(trace) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 93
def current_trace=(trace)
  t { "setting current_trace=#{trace ? trace.uuid : 'nil'}; thread=#{Thread.current.object_id}" }
  @trace_info.current = trace
end
disable()
Alias for: mute
disabled?()
Alias for: muted?
done(span, meta = nil) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 271
def done(span, meta = nil)
  return unless (trace = @trace_info.current)
  trace.done(span, meta)
end
finalize_endpoint_segment(trace) click to toggle source

Because GraphQL can return multiple results, each of which may have their own success/error states, we need to set the skylight segment as follows:

  • when all queries have errors: “error”

  • when some queries have errors: “<rendered format>+error”

  • when no queries have errors: “<rendered format>”

<rendered format> will be determined by the Rails controller as usual. See Instrumenter#finalize_endpoint_segment for the actual segment/error assignment.

# File lib/skylight/core/instrumenter.rb, line 330
def finalize_endpoint_segment(trace)
  return unless (segment = trace.segment)

  segment = case trace.compound_response_error_status
            when :all
              "error"
            when :partial
              "#{segment}+error"
            else
              segment
            end

  trace.endpoint += "<sk-segment>#{segment}</sk-segment>"
end
handle_instrumenter_error(trace, e) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 305
def handle_instrumenter_error(trace, e)
  warn "failed to submit trace to worker; trace=%s, err=%s", trace.uuid, e
  t { "BACKTRACE:\n#{e.backtrace.join("\n")}" }
  false
end
ignore?(trace) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 311
def ignore?(trace)
  config.ignored_endpoints.include?(trace.endpoint)
end
instrument(cat, title = nil, desc = nil, meta = nil) { || ... } click to toggle source
# File lib/skylight/core/instrumenter.rb, line 212
def instrument(cat, title = nil, desc = nil, meta = nil)
  raise ArgumentError, "cat is required" unless cat

  if muted?
    return yield if block_given?
    return
  end

  unless (trace = @trace_info.current)
    return yield if block_given?
    return
  end

  cat = cat.to_s

  unless match?(cat, Skylight::CATEGORY_REGEX)
    warn "invalid skylight instrumentation category; trace=%s; value=%s", trace.uuid, cat
    return yield if block_given?
    return
  end

  cat = "other.#{cat}" unless match?(cat, Skylight::TIER_REGEX)

  unless (sp = trace.instrument(cat, title, desc, meta))
    return yield if block_given?
    return
  end

  return sp unless block_given?

  meta = {}
  begin
    yield sp
  rescue Exception => e
    meta = { exception: [e.class.name, e.message], exception_object: e }
    raise e
  ensure
    trace.done(sp, meta)
  end
end
limited_description(description) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 276
def limited_description(description)
  endpoint = @trace_info.current.endpoint

  if description
    if native_track_desc(endpoint, description)
      description
    else
      TOO_MANY_UNIQUES
    end
  end
end
log_context() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 69
def log_context
  @log_context ||= { inst: uuid }
end
match?(string, regex) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 208
def match?(string, regex)
  self.class.match?(string, regex)
end
mute() { || ... } click to toggle source
# File lib/skylight/core/instrumenter.rb, line 110
def mute
  old_muted = muted?
  self.muted = true
  yield if block_given?
ensure
  self.muted = old_muted
end
Also aliased as: disable
muted=(val) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 102
def muted=(val)
  @trace_info.muted = val
end
muted?() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 106
def muted?
  @trace_info.muted?
end
Also aliased as: disabled?
native_start() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 73
def native_start
  raise "not implemented"
end
native_stop() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 77
def native_stop
  raise "not implemented"
end
native_submit_trace(_trace) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 85
def native_submit_trace(_trace)
  raise "not implemented"
end
native_track_desc(_endpoint, _description) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 81
def native_track_desc(_endpoint, _description)
  raise "not implemented"
end
poison!() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 263
def poison!
  @poisoned = true
end
poisoned?() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 267
def poisoned?
  @poisoned
end
process(trace) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 288
def process(trace)
  t { fmt "processing trace=#{trace.uuid}" }

  if ignore?(trace)
    t { fmt "ignoring trace=#{trace.uuid}" }
    return false
  end

  begin
    finalize_endpoint_segment(trace)
    native_submit_trace(trace)
    true
  rescue => e
    handle_instrumenter_error(trace, e)
  end
end
process_sql(sql) click to toggle source

Return [title, sql]

# File lib/skylight/core/instrumenter.rb, line 316
def process_sql(sql)
  [nil, sql]
end
shutdown() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 170
def shutdown
  @subscriber.unregister!
  native_stop
end
silence_warnings(context) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 126
def silence_warnings(context)
  @warnings_silenced || @mutex.synchronize do
    @warnings_silenced ||= {}
  end

  @warnings_silenced[context] = true
end
span_correlation_header(span) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 253
def span_correlation_header(span)
  return unless (trace = @trace_info.current)
  trace.span_correlation_header(span)
end
start!() click to toggle source
# File lib/skylight/core/instrumenter.rb, line 141
def start!
  # We do this here since we can't report these issues via Gem install without stopping install entirely.
  check_install!

  t { "starting instrumenter" }

  unless config.validate_with_server
    log_error "invalid config"
    return
  end

  t { "starting native instrumenter" }
  unless native_start
    warn "failed to start instrumenter"
    return
  end

  config.gc.enable
  @subscriber.register!

  ActiveSupport::Notifications.instrument("started_instrumenter.skylight", instrumenter: self)

  self
rescue Exception => e
  log_error "failed to start instrumenter; msg=%s; config=%s", e.message, config.inspect
  t { e.backtrace.join("\n") }
  nil
end
trace(endpoint, cat, title = nil, desc = nil, meta: nil, segment: nil, component: nil) { |trace| ... } click to toggle source
# File lib/skylight/core/instrumenter.rb, line 175
def trace(endpoint, cat, title = nil, desc = nil, meta: nil, segment: nil, component: nil)
  # If a trace is already in progress, continue with that one
  if (trace = @trace_info.current)
    return yield(trace) if block_given?
    return trace
  end

  begin
    trace = self.class.trace_class.new(self, endpoint, Util::Clock.nanos, cat, title, desc, meta: meta, segment: segment, component: component)
  rescue Exception => e
    log_error e.message
    t { e.backtrace.join("\n") }
    return
  end

  @trace_info.current = trace
  return trace unless block_given?

  begin
    yield trace
  ensure
    @trace_info.current = nil
    t { "instrumenter submitting trace; trace=#{trace.uuid}" }
    trace.submit
  end
end
unmute() { || ... } click to toggle source
# File lib/skylight/core/instrumenter.rb, line 118
def unmute
  old_muted = muted?
  self.muted = false
  yield if block_given?
ensure
  self.muted = old_muted
end
warnings_silenced?(context) click to toggle source
# File lib/skylight/core/instrumenter.rb, line 134
def warnings_silenced?(context)
  @warnings_silenced && @warnings_silenced[context]
end