Module: RailsOtelContext::SourceLocation

Included in:
CallContextProcessor
Defined in:
lib/rails_otel_context/source_location.rb

Overview

Shared call-site extraction for DB adapters and CallContextProcessor.

Every adapter (Trilogy, PG, MySQL2) includes this on class << self and calls call_site_for_app after (or around) the query. Because the adapter is closer to user code in the call stack than CallContextProcessor#on_start is, the walk reaches the app frame in fewer iterations — and returns class + method + filepath + lineno in one shot.

CallContextProcessor includes this too so it can share the same logic in its stack-walk fallback path.

Instance Method Summary collapse

Instance Method Details

#apply_call_site_to_span(span, site) ⇒ Object

Applies all four call-site attributes to span in one go.



40
41
42
43
44
45
46
47
# File 'lib/rails_otel_context/source_location.rb', line 40

def apply_call_site_to_span(span, site)
  return unless site && span.context.valid?

  span.set_attribute('code.namespace', site[:class_name])
  span.set_attribute('code.function',  site[:method_name]) if site[:method_name]
  span.set_attribute('code.filepath',  site[:filepath])
  span.set_attribute('code.lineno',    site[:lineno]) if site[:lineno]
end

#apply_source_to_span(span, source) ⇒ Object

Legacy helper — use apply_call_site_to_span for new code.



83
84
85
86
87
88
# File 'lib/rails_otel_context/source_location.rb', line 83

def apply_source_to_span(span, source)
  return unless source

  span.set_attribute('code.filepath', source[0])
  span.set_attribute('code.lineno',   source[1])
end

#call_site_for_appObject

Returns the first app-code frame as a Hash:

{ class_name:, method_name:, filepath:, lineno: }

Returns nil when no app frame is found or the feature is unavailable. Requires app_root to be defined on the including object.



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/rails_otel_context/source_location.rb', line 25

def call_site_for_app
  return unless Thread.respond_to?(:each_caller_location)

  Thread.each_caller_location do |location|
    path = location.absolute_path || location.path
    next unless path&.start_with?(app_root)
    next if path.include?('/gems/')

    return build_call_site(location, path)
  end

  nil
end

#source_location_for_appObject

Legacy helper kept for Redis and ClickHouse adapters that only need filepath + lineno. Migrate those adapters to call_site_for_app + apply_call_site_to_span to remove this.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rails_otel_context/source_location.rb', line 67

def source_location_for_app
  return unless Thread.respond_to?(:each_caller_location)

  prefix = app_root_prefix
  Thread.each_caller_location do |location|
    path = location.absolute_path || location.path
    next unless path&.start_with?(app_root)
    next if path.include?('/gems/')

    return [path.delete_prefix(prefix), location.lineno]
  end

  nil
end

#with_call_site_frameObject

Wraps a block with the nearest app-code frame pushed into FrameContext. Used by DB adapters to make the call-site available to CallContextProcessor#on_start for the child span created inside the block. Uses with_frame (not push/pop) so nested frames are correctly restored.



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rails_otel_context/source_location.rb', line 53

def with_call_site_frame(&)
  site = call_site_for_app
  if site
    FrameContext.with_frame(
      class_name: site[:class_name], method_name: site[:method_name],
      filepath: site[:filepath], lineno: site[:lineno], &
    )
  else
    yield
  end
end