rails-otel-context 0.9.6 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e06fe4be3a8bd4949ad32d7fbe9e3dac1090d9044b997c7427feee131776564
4
- data.tar.gz: 61e3bc83de1debb6c9cafce615a8c7328b751bdbfb2ffa5bdf037cbae1a01a86
3
+ metadata.gz: f8ea9eb65d7e405bbd14a39889bbad983edbba5c4bdcce252157d426a2372bc6
4
+ data.tar.gz: c70ddac87d64c8359fe82fe142bda62e4968b3429ea6944796b475270310d1d7
5
5
  SHA512:
6
- metadata.gz: 9424d03a617834466c9f52d7fb870f1a5dfdbd39c7966cf128c5df1bd87a497af38baff4be7838a9181f9e3c23e1659299c15b27d01d22d9af295c3cbbe4b4d3
7
- data.tar.gz: 6201a8a0974a549ca93e3587d0fd416f57cc92c3594922d6e72685b9641477d2800ccf2e9b7c5d72d1504bbf877c8a3c47949e272cfbd647a3b697a61de7eaf1
6
+ metadata.gz: cfee7357103d1336be233b9b6724c1b6678117f7fcd3e57dda75ca473a3a608c8f511e7151db29cd9bce34627fcd8d0b482fcdb640812941c960385bf57acadd
7
+ data.tar.gz: 15888432fb759223a87cdf35f0dd9ae00c07ac59ef038b06bd49644968996b23fc910b0cca0f0912857bf8a4101ad9d005aa66596cef5b4a1e29de68a12486c8
@@ -32,12 +32,11 @@ module RailsOtelContext
32
32
  end
33
33
  end
34
34
 
35
- # AR context and span renaming handled by CallContextProcessor.apply_db_context.
35
+ # Push call-site into FrameContext BEFORE super so the OTel child span
36
+ # created inside super picks it up via CallContextProcessor#on_start.
36
37
  %i[query prepare].each do |method_name|
37
38
  define_method(method_name) do |*args|
38
- result = super(*args)
39
- mod.apply_call_site_to_span(OpenTelemetry::Trace.current_span, mod.call_site_for_app)
40
- result
39
+ mod.with_call_site_frame { super(*args) }
41
40
  end
42
41
  end
43
42
  end
@@ -42,16 +42,14 @@ module RailsOtelContext
42
42
  end
43
43
  end
44
44
 
45
- # AR context and span renaming handled by CallContextProcessor.apply_db_context.
45
+ # Push call-site into FrameContext BEFORE super so the OTel child span
46
+ # created inside super picks it up via CallContextProcessor#on_start.
46
47
  methods.each do |method_name|
47
48
  define_method(method_name) do |*args, &user_block|
48
- # Capture before super: PG yields into a block so the original
49
- # call stack is only visible here, not inside the result block.
50
- site = mod.call_site_for_app
51
-
52
- super(*args) do |result|
53
- mod.apply_call_site_to_span(OpenTelemetry::Trace.current_span, site)
54
- user_block ? user_block.call(result) : result
49
+ mod.with_call_site_frame do
50
+ super(*args) do |result|
51
+ user_block ? user_block.call(result) : result
52
+ end
55
53
  end
56
54
  end
57
55
  end
@@ -32,11 +32,10 @@ module RailsOtelContext
32
32
  end
33
33
  end
34
34
 
35
- # AR context and span renaming handled by CallContextProcessor.apply_db_context.
35
+ # Push call-site into FrameContext BEFORE super so the OTel child span
36
+ # created inside super picks it up via CallContextProcessor#on_start.
36
37
  define_method(:query) do |sql|
37
- result = super(sql)
38
- mod.apply_call_site_to_span(OpenTelemetry::Trace.current_span, mod.call_site_for_app)
39
- result
38
+ mod.with_call_site_frame { super(sql) }
40
39
  end
41
40
  end
42
41
 
@@ -82,17 +82,18 @@ module RailsOtelContext
82
82
  def apply_call_context(span)
83
83
  # Explicit override: app code called FrameContext.with_frame (or Frameable).
84
84
  # O(1) — no stack walk. Takes priority over automatic detection.
85
- pushed = FrameContext.current
86
- if pushed
87
- span.set_attribute('code.namespace', pushed[:class_name])
88
- span.set_attribute('code.function', pushed[:method_name]) if pushed[:method_name]
89
- return
90
- end
85
+ # DB adapters push filepath/lineno too so the child span gets full call-site info.
86
+ site = FrameContext.current
87
+ unless site
88
+ # Default: walk the call stack to find the nearest app-code frame.
89
+ return unless Thread.respond_to?(:each_caller_location)
91
90
 
92
- # Default: walk the call stack to find the nearest app-code frame.
93
- return unless Thread.respond_to?(:each_caller_location)
91
+ site = call_site_for_app
92
+ end
93
+ set_call_site_attributes(span, site)
94
+ end
94
95
 
95
- site = call_site_for_app
96
+ def set_call_site_attributes(span, site)
96
97
  return unless site
97
98
 
98
99
  span.set_attribute('code.namespace', site[:class_name])
@@ -27,17 +27,19 @@ module RailsOtelContext
27
27
  class << self
28
28
  # Pushes +class_name+/+method_name+ for the duration of the block,
29
29
  # restoring whatever was pushed before (supports nesting).
30
- def with_frame(class_name:, method_name:)
30
+ # Optional +filepath:+ and +lineno:+ are carried through to the span
31
+ # processor so DB adapter call-site info survives the span lifecycle.
32
+ def with_frame(class_name:, method_name:, filepath: nil, lineno: nil)
31
33
  prev = Thread.current[FRAME_KEY]
32
- Thread.current[FRAME_KEY] = { class_name: class_name, method_name: method_name }.freeze
34
+ Thread.current[FRAME_KEY] = build_frame(class_name, method_name, filepath, lineno)
33
35
  yield
34
36
  ensure
35
37
  Thread.current[FRAME_KEY] = prev
36
38
  end
37
39
 
38
40
  # Manual push without a block. Caller must call +pop+ in an ensure.
39
- def push(class_name:, method_name:)
40
- Thread.current[FRAME_KEY] = { class_name: class_name, method_name: method_name }.freeze
41
+ def push(class_name:, method_name:, filepath: nil, lineno: nil)
42
+ Thread.current[FRAME_KEY] = build_frame(class_name, method_name, filepath, lineno)
41
43
  end
42
44
 
43
45
  # Clears the pushed frame. Pair with +push+ in an ensure block.
@@ -51,6 +53,15 @@ module RailsOtelContext
51
53
  end
52
54
 
53
55
  alias clear! pop
56
+
57
+ private
58
+
59
+ def build_frame(class_name, method_name, filepath, lineno)
60
+ frame = { class_name: class_name, method_name: method_name }
61
+ frame[:filepath] = filepath if filepath
62
+ frame[:lineno] = lineno if lineno
63
+ frame.freeze
64
+ end
54
65
  end
55
66
  end
56
67
 
@@ -46,6 +46,22 @@ module RailsOtelContext
46
46
  span.set_attribute('code.lineno', site[:lineno]) if site[:lineno]
47
47
  end
48
48
 
49
+ # Wraps a block with the nearest app-code frame pushed into FrameContext.
50
+ # Used by DB adapters to make the call-site available to
51
+ # CallContextProcessor#on_start for the child span created inside the block.
52
+ # Uses with_frame (not push/pop) so nested frames are correctly restored.
53
+ def with_call_site_frame(&)
54
+ site = call_site_for_app
55
+ if site
56
+ FrameContext.with_frame(
57
+ class_name: site[:class_name], method_name: site[:method_name],
58
+ filepath: site[:filepath], lineno: site[:lineno], &
59
+ )
60
+ else
61
+ yield
62
+ end
63
+ end
64
+
49
65
  # Legacy helper kept for Redis and ClickHouse adapters that only need filepath + lineno.
50
66
  # Migrate those adapters to call_site_for_app + apply_call_site_to_span to remove this.
51
67
  def source_location_for_app
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsOtelContext
4
- VERSION = '0.9.6'
4
+ VERSION = '0.9.7'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-otel-context
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.6
4
+ version: 0.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Last9