rails-otel-context 0.9.7 → 0.9.8

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: f8ea9eb65d7e405bbd14a39889bbad983edbba5c4bdcce252157d426a2372bc6
4
- data.tar.gz: c70ddac87d64c8359fe82fe142bda62e4968b3429ea6944796b475270310d1d7
3
+ metadata.gz: 0aa66c7dfd0480bd0a9100e00fbea58eaab5ec0153dd5cb4a82b8df840092787
4
+ data.tar.gz: 9743746552b3a934798f2812a61f9d4f72f5c296ba75dae943b9dcb5120e8f5e
5
5
  SHA512:
6
- metadata.gz: cfee7357103d1336be233b9b6724c1b6678117f7fcd3e57dda75ca473a3a608c8f511e7151db29cd9bce34627fcd8d0b482fcdb640812941c960385bf57acadd
7
- data.tar.gz: 15888432fb759223a87cdf35f0dd9ae00c07ac59ef038b06bd49644968996b23fc910b0cca0f0912857bf8a4101ad9d005aa66596cef5b4a1e29de68a12486c8
6
+ metadata.gz: 40c59f1db646b5d159e23b36d9f651b4809ee19dc8f797ef9b6a5d261810ccfabc7d50c4460e01ac1b132058e1a28d9312b235d0c66e2f99fa6503f98a5ce4b9
7
+ data.tar.gz: 828f792d02e5ff2c7588d946f8535f5d41f25ad84e55f22854f73e007cb6bf6c39eaf1f05ab40eedae6a37c0d8d5c9e952d127428255221d47bee6d72e51170f
@@ -12,11 +12,12 @@ module RailsOtelContext
12
12
  # Relation#exec_queries. This handles lazy scopes like
13
13
  # Transaction.recent_completed.to_a where the scope method returns before
14
14
  # SQL fires.
15
- module ActiveRecordContext
16
- THREAD_KEY = :_rails_otel_ctx_ar
17
- SCOPE_THREAD_KEY = :_rails_otel_ctx_scope
18
- DB_SLOW_ATTR = 'db.slow'
19
- private_constant :THREAD_KEY, :SCOPE_THREAD_KEY
15
+ module ActiveRecordContext # rubocop:disable Metrics/ModuleLength
16
+ THREAD_KEY = :_rails_otel_ctx_ar
17
+ SCOPE_THREAD_KEY = :_rails_otel_ctx_scope
18
+ PENDING_PREPARE_KEY = :_rails_otel_ctx_pending_prepare_spans
19
+ DB_SLOW_ATTR = 'db.slow'
20
+ private_constant :THREAD_KEY, :SCOPE_THREAD_KEY, :PENDING_PREPARE_KEY
20
21
 
21
22
  # Frozen regex — only the verb regex remains; table extraction uses index+slice.
22
23
  SQL_VERB_RE = /\A(\w+)/i
@@ -102,18 +103,29 @@ module RailsOtelContext
102
103
  ctx[:async] = true if payload[:async]
103
104
  Thread.current[THREAD_KEY] = ctx
104
105
 
106
+ return unless defined?(OpenTelemetry::Trace)
107
+
105
108
  # Enrich the current span directly. When OTel instruments via driver-level
106
109
  # prepend (Trilogy, PG, Mysql2), the span is created BEFORE this notification
107
110
  # fires, so CallContextProcessor#on_start sees nil AR context. Applying here
108
111
  # fixes those spans after the fact.
109
- return unless defined?(OpenTelemetry::Trace)
110
-
111
112
  ActiveRecordContext.apply_to_span(OpenTelemetry::Trace.current_span, ctx)
113
+
114
+ # Retroactively enrich any PREPARE spans that finished before this notification
115
+ # fired. PG's prepared-statement flow sends PREPARE then EXECUTE as separate wire
116
+ # operations; the PREPARE span finishes before sql.active_record starts, so it
117
+ # never sees AR context. CallContextProcessor#on_finish stashes those spans here.
118
+ pending = Thread.current[PENDING_PREPARE_KEY]
119
+ return unless pending
120
+
121
+ pending.each { |s| ActiveRecordContext.retroactively_apply_to_span(s, ctx) }
122
+ Thread.current[PENDING_PREPARE_KEY] = nil
112
123
  end
113
124
 
114
125
  def finish(_name, _id, _payload)
115
126
  ensure
116
127
  Thread.current[THREAD_KEY] = nil
128
+ Thread.current[PENDING_PREPARE_KEY] = nil # clear any leftovers from skipped notifications
117
129
  end
118
130
  end
119
131
 
@@ -173,8 +185,16 @@ module RailsOtelContext
173
185
  end
174
186
 
175
187
  def clear!
176
- Thread.current[THREAD_KEY] = nil
177
- Thread.current[SCOPE_THREAD_KEY] = nil
188
+ Thread.current[THREAD_KEY] = nil
189
+ Thread.current[SCOPE_THREAD_KEY] = nil
190
+ Thread.current[PENDING_PREPARE_KEY] = nil
191
+ end
192
+
193
+ # Called from CallContextProcessor#on_finish when a PREPARE span finishes
194
+ # before its sql.active_record notification. Stashed spans are flushed by
195
+ # Subscriber#start when the notification fires.
196
+ def stash_prepare_span(span)
197
+ (Thread.current[PENDING_PREPARE_KEY] ||= []) << span
178
198
  end
179
199
 
180
200
  # Test helpers: set AR context directly for unit tests.
@@ -186,6 +206,34 @@ module RailsOtelContext
186
206
  Thread.current[SCOPE_THREAD_KEY] = scope_name
187
207
  end
188
208
 
209
+ # Retroactively applies AR context to a finished span (e.g. PREPARE spans that
210
+ # finished before sql.active_record fired). Uses direct @attributes mutation
211
+ # because span.recording? is false — set_attribute would be a no-op.
212
+ def retroactively_apply_to_span(span, ctx)
213
+ attrs = span.instance_variable_get(:@attributes)
214
+ return unless attrs.respond_to?(:store)
215
+
216
+ attrs.store(AR_MODEL_ATTR, ctx[:model_name]) if ctx[:model_name]
217
+ attrs.store(AR_METHOD_ATTR, ctx[:method_name]) if ctx[:method_name]
218
+ attrs.store(AR_SCOPE_ATTR, ctx[:scope_name]) if ctx[:scope_name]
219
+
220
+ formatter = RailsOtelContext.configuration.span_name_formatter
221
+ return unless formatter && span.respond_to?(:name) && attrs.key?('db.system')
222
+
223
+ ar_ctx = ctx.dup
224
+ ar_ctx[:code_namespace] = attrs['code.namespace']
225
+ ar_ctx[:code_function] = attrs['code.function']
226
+
227
+ original_name = span.name
228
+ new_name = formatter.call(original_name, ar_ctx)
229
+ return unless new_name && new_name != original_name
230
+
231
+ attrs.store(ORIG_NAME_ATTR, original_name)
232
+ span.instance_variable_set(:@name, new_name)
233
+ rescue StandardError
234
+ nil
235
+ end
236
+
189
237
  # Applies AR context directly to a span. Used by Subscriber#start to enrich spans
190
238
  # created by driver-level OTel instrumentation (Trilogy, PG) before our notification
191
239
  # subscriber runs. Also reads code.namespace/code.function already set by
@@ -5,7 +5,14 @@ module RailsOtelContext
5
5
  module Clickhouse
6
6
  module_function
7
7
 
8
- CANDIDATE_METHODS = %i[query select insert execute command].freeze
8
+ # click_house gem v1.x used :query/:select; v2.x uses :select_all/:select_one/:select_value.
9
+ # We list all known variants so install! picks whichever the loaded gem version defines.
10
+ CANDIDATE_METHODS = %i[
11
+ select_all select_one select_value
12
+ insert insert_compact insert_rows
13
+ execute command
14
+ query select
15
+ ].freeze
9
16
  REENTRANCY_KEY = :_rails_otel_ctx_clickhouse_instrumenting
10
17
 
11
18
  def install!(app_root:)
@@ -43,6 +50,52 @@ module RailsOtelContext
43
50
  @patch_modules[key] ||= build_patch_module(methods)
44
51
  end
45
52
 
53
+ # Maps compound gem method names to their SQL verb for span naming.
54
+ # select_all/select_one/select_value → SELECT; insert_* → INSERT.
55
+ METHOD_OP_ALIAS = {
56
+ 'SELECT_ALL' => 'SELECT',
57
+ 'SELECT_ONE' => 'SELECT',
58
+ 'SELECT_VALUE' => 'SELECT',
59
+ 'INSERT_COMPACT' => 'INSERT',
60
+ 'INSERT_ROWS' => 'INSERT'
61
+ }.freeze
62
+
63
+ # Derives a human-readable span name from the SQL statement.
64
+ # Follows OTel DB convention: "{sql_verb} {table}".
65
+ # Falls back to "{method_op} clickhouse" when the statement is absent
66
+ # or cannot be parsed (e.g. raw ClickHouse commands with no FROM clause).
67
+ #
68
+ # Accepts an optional pre-parsed +table_name+ to avoid a second regex scan
69
+ # when the caller already holds the result of parse_table.
70
+ def span_name_for(statement, method_op, table_name: nil)
71
+ effective_op = METHOD_OP_ALIAS.fetch(method_op, method_op)
72
+ return "#{effective_op} clickhouse" unless statement.is_a?(String)
73
+
74
+ sql_verb = statement.lstrip.split(/\s/, 2).first&.upcase
75
+ table_name = parse_table(statement).last if table_name.nil?
76
+
77
+ if sql_verb && table_name
78
+ "#{sql_verb} #{table_name}"
79
+ elsif sql_verb
80
+ "#{sql_verb} clickhouse"
81
+ else
82
+ "#{effective_op} clickhouse"
83
+ end
84
+ end
85
+
86
+ # Returns [db_name, table_name] extracted from the SQL statement.
87
+ # db_name is the schema prefix (e.g. "mailgun_analytics"), nil when absent.
88
+ # table_name is the bare table (e.g. "mailgun_events"), nil when not found.
89
+ def parse_table(statement)
90
+ return [nil, nil] unless statement.is_a?(String)
91
+
92
+ qualified = statement.match(/(?:\bFROM\b|\bINTO\b|\bUPDATE\b)\s+([\w.]+)/i)&.captures&.first
93
+ return [nil, nil] unless qualified
94
+
95
+ parts = qualified.split('.')
96
+ parts.size > 1 ? [parts[0..-2].join('.'), parts.last] : [nil, parts.first]
97
+ end
98
+
46
99
  def build_patch_module(methods)
47
100
  mod = Module.new do
48
101
  class << self
@@ -55,11 +108,12 @@ module RailsOtelContext
55
108
  end
56
109
  end
57
110
 
58
- # AR context and span renaming handled by CallContextProcessor.apply_db_context.
59
111
  reentrancy_key = RailsOtelContext::Adapters::Clickhouse::REENTRANCY_KEY
60
112
 
61
113
  methods.each do |method_name|
62
- operation = method_name.to_s.upcase.freeze
114
+ method_op = RailsOtelContext::Adapters::Clickhouse::METHOD_OP_ALIAS
115
+ .fetch(method_name.to_s.upcase, method_name.to_s.upcase)
116
+ .freeze
63
117
 
64
118
  define_method(method_name) do |*args, &block|
65
119
  return super(*args, &block) if Thread.current[reentrancy_key]
@@ -67,16 +121,45 @@ module RailsOtelContext
67
121
  site = mod.call_site_for_app
68
122
  statement = args.first.is_a?(String) ? args.first : nil
69
123
 
124
+ # Parse table once — span_name_for accepts the pre-parsed value to skip
125
+ # the internal regex scan, and we reuse db_name for db.name attribute.
126
+ db_name, table_name = RailsOtelContext::Adapters::Clickhouse.parse_table(statement)
127
+ sql_verb = statement ? statement.lstrip.split(/\s/, 2).first&.upcase || method_op : method_op
128
+ span_name = RailsOtelContext::Adapters::Clickhouse.span_name_for(
129
+ statement, method_op, table_name: table_name
130
+ )
131
+
70
132
  tracer = OpenTelemetry.tracer_provider.tracer('rails-otel-context-clickhouse')
71
133
  Thread.current[reentrancy_key] = true
72
134
 
73
- tracer.in_span("#{operation} clickhouse", kind: :client) do |span|
74
- span.set_attribute('db.system', 'clickhouse')
75
- span.set_attribute('db.operation', operation)
76
- span.set_attribute('db.statement', statement) if statement
135
+ tracer.in_span(span_name, kind: :client) do |span|
136
+ span.set_attribute('db.system', 'clickhouse')
137
+ span.set_attribute('db.operation', sql_verb)
138
+ span.set_attribute('db.statement', statement) if statement
139
+ span.set_attribute('db.name', db_name) if db_name
140
+ span.set_attribute('db.sql.table', table_name) if table_name
77
141
 
78
142
  result = super(*args, &block)
79
143
  mod.apply_call_site_to_span(span, site)
144
+
145
+ # ClickHouse spans don't fire sql.active_record notifications, so
146
+ # CallContextProcessor#apply_db_context never runs for them.
147
+ # Apply the span_name_formatter here with a synthetic AR-shaped context
148
+ # built from code.namespace/code.function set by apply_call_site_to_span.
149
+ formatter = RailsOtelContext.configuration.span_name_formatter
150
+ code_ns = formatter && span.respond_to?(:attributes) &&
151
+ span.attributes['code.namespace']
152
+ if code_ns
153
+ fn = span.attributes['code.function']
154
+ ar_ctx = { model_name: code_ns, method_name: fn, scope_name: nil,
155
+ code_namespace: code_ns, code_function: fn }
156
+ new_name = formatter.call(span_name, ar_ctx)
157
+ if new_name && new_name != span_name
158
+ span.set_attribute('l9.orig.name', span_name)
159
+ span.name = new_name
160
+ end
161
+ end
162
+
80
163
  result
81
164
  end
82
165
  ensure
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOtelContext
4
+ module Adapters
5
+ module ConnectionPool
6
+ TRACER_NAME = 'rails_otel_context'
7
+ SPAN_NAME = 'active_record.connection_checkout'
8
+ private_constant :TRACER_NAME, :SPAN_NAME
9
+
10
+ module_function
11
+
12
+ def install!
13
+ return unless defined?(::ActiveRecord::ConnectionAdapters::ConnectionPool)
14
+
15
+ patch_module = patch_module_for
16
+ return if ::ActiveRecord::ConnectionAdapters::ConnectionPool.ancestors.include?(patch_module)
17
+
18
+ ::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(patch_module)
19
+ end
20
+
21
+ def patch_module_for
22
+ @patch_module ||= build_patch_module
23
+ end
24
+
25
+ def build_patch_module
26
+ # Capture as locals so define_method closes over them — constants declared
27
+ # private_constant are inaccessible from the anonymous module's def scope.
28
+ tracer_name = TRACER_NAME
29
+ span_name = SPAN_NAME
30
+ # Cached lazily on first checkout — tracer_provider may not be fully
31
+ # configured when install! runs at boot.
32
+ cached_tracer = nil
33
+
34
+ Module.new do
35
+ define_method(:checkout) do |checkout_timeout = @checkout_timeout|
36
+ # Rails 7.2+ fast path: pinned connection bypasses pool wait entirely.
37
+ # No span needed — duration would be ~0ms and it's misleading noise.
38
+ return super(checkout_timeout) if @pinned_connection
39
+
40
+ cached_tracer ||= OpenTelemetry.tracer_provider.tracer(tracer_name)
41
+
42
+ cached_tracer.in_span(span_name) do |span|
43
+ result = super(checkout_timeout)
44
+
45
+ # stat acquires the pool's monitor lock and iterates @connections —
46
+ # acceptable for opt-in diagnostics. Avoid enabling this permanently
47
+ # on high-traffic pools where lock contention is already a concern.
48
+ pool_stat = stat
49
+ span.set_attribute('db.pool.size', pool_stat[:size])
50
+ span.set_attribute('db.pool.busy', pool_stat[:busy])
51
+ span.set_attribute('db.pool.idle', pool_stat[:idle])
52
+ span.set_attribute('db.pool.waiting', pool_stat[:waiting])
53
+
54
+ result
55
+ end
56
+ end
57
+ end
58
+ end
59
+ private_class_method :patch_module_for, :build_patch_module
60
+ end
61
+ end
62
+ end
@@ -5,6 +5,7 @@ require 'rails_otel_context/adapters/mysql2'
5
5
  require 'rails_otel_context/adapters/trilogy'
6
6
  require 'rails_otel_context/adapters/redis'
7
7
  require 'rails_otel_context/adapters/clickhouse'
8
+ require 'rails_otel_context/adapters/connection_pool'
8
9
 
9
10
  module RailsOtelContext
10
11
  module Adapters
@@ -16,6 +17,7 @@ module RailsOtelContext
16
17
  Trilogy.install!(app_root: app_root)
17
18
  Redis.install!(app_root: app_root) if config.redis_source_enabled
18
19
  Clickhouse.install!(app_root: app_root) if config.clickhouse_enabled
20
+ ConnectionPool.install! if config.connection_pool_tracing_enabled
19
21
  end
20
22
  end
21
23
  end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOtelContext
4
+ # Rack middleware that captures request and response bodies as OpenTelemetry
5
+ # span attributes. Works with any OTel Rack instrumentation — the middleware
6
+ # must sit inside (after) the span-creating middleware so current_span is set.
7
+ #
8
+ # Usage:
9
+ # # config/application.rb (or an initializer after OTel is configured)
10
+ # config.middleware.use RailsOtelContext::BodyCapture
11
+ #
12
+ # # With options:
13
+ # config.middleware.use RailsOtelContext::BodyCapture,
14
+ # on_error_only: true,
15
+ # max_bytes: 4096
16
+ #
17
+ # Span attributes set:
18
+ # http.request.body — captured request body (when content type matches)
19
+ # http.response.body — captured response body (when content type matches)
20
+ class BodyCapture
21
+ DEFAULT_CONTENT_TYPES = %w[application/json application/xml text/plain].freeze
22
+ DEFAULT_EXCLUDE_PATHS = %w[/health /ready /metrics].freeze
23
+ DEFAULT_MAX_BYTES = 8_192
24
+ TRUNCATED_SUFFIX = '...[TRUNCATED]'
25
+ private_constant :DEFAULT_CONTENT_TYPES, :DEFAULT_EXCLUDE_PATHS,
26
+ :DEFAULT_MAX_BYTES, :TRUNCATED_SUFFIX
27
+
28
+ def initialize(app, # rubocop:disable Metrics/ParameterLists
29
+ capture_request: true,
30
+ capture_response: true,
31
+ max_bytes: DEFAULT_MAX_BYTES,
32
+ on_error_only: false,
33
+ content_types: DEFAULT_CONTENT_TYPES,
34
+ include_paths: [],
35
+ exclude_paths: DEFAULT_EXCLUDE_PATHS)
36
+ @app = app
37
+ @capture_request = capture_request
38
+ @capture_response = capture_response
39
+ @max_bytes = max_bytes
40
+ @on_error_only = on_error_only
41
+ @content_types = content_types
42
+ @include_paths = include_paths
43
+ @exclude_paths = exclude_paths
44
+ end
45
+
46
+ def call(env)
47
+ return @app.call(env) unless should_capture?(env['PATH_INFO'])
48
+
49
+ request_str = read_request(env)
50
+ status, headers, body = @app.call(env)
51
+
52
+ # With on_error_only, skip body drain on successful responses — no buffering
53
+ # overhead on the happy path. (Synchronous Rack means we know status before
54
+ # deciding to drain, unlike async frameworks that must always buffer.)
55
+ should_record = !@on_error_only || status >= 400
56
+
57
+ if should_record && @capture_response
58
+ body, response_str = drain_response(body, headers)
59
+ end
60
+
61
+ set_span_attributes(request_str, response_str) if should_record
62
+
63
+ [status, headers, body]
64
+ end
65
+
66
+ private
67
+
68
+ def should_capture?(path)
69
+ return false if @exclude_paths.any? { |p| path.start_with?(p) }
70
+ return true if @include_paths.empty?
71
+
72
+ @include_paths.any? { |p| path.start_with?(p) }
73
+ end
74
+
75
+ def allowed_content_type?(content_type)
76
+ return false unless content_type && !content_type.empty?
77
+ return true if @content_types.empty?
78
+
79
+ @content_types.any? { |ct| content_type.include?(ct) }
80
+ end
81
+
82
+ def read_request(env)
83
+ return unless @capture_request
84
+ return unless allowed_content_type?(env['CONTENT_TYPE'])
85
+
86
+ input = env['rack.input']
87
+ return unless input
88
+
89
+ raw = input.read
90
+ input.rewind
91
+ cap(raw)
92
+ end
93
+
94
+ def drain_response(body, headers)
95
+ chunks = body.map { |chunk| chunk }
96
+ body.close if body.respond_to?(:close)
97
+
98
+ content_type = headers['Content-Type'] || headers['content-type']
99
+ body_str = cap(chunks.join) if allowed_content_type?(content_type)
100
+
101
+ [chunks, body_str]
102
+ end
103
+
104
+ def set_span_attributes(request_str, response_str)
105
+ return unless defined?(OpenTelemetry)
106
+
107
+ span = OpenTelemetry::Trace.current_span
108
+ return unless span.context.valid?
109
+
110
+ span.set_attribute('http.request.body', request_str) if request_str
111
+ span.set_attribute('http.response.body', response_str) if response_str
112
+ end
113
+
114
+ def cap(str)
115
+ return nil if str.nil? || str.empty?
116
+ return str if str.bytesize <= @max_bytes
117
+
118
+ # scrub cleans up any incomplete multibyte sequence at the slice boundary
119
+ str.byteslice(0, @max_bytes).scrub + TRUNCATED_SUFFIX
120
+ end
121
+ end
122
+ end
@@ -52,8 +52,14 @@ module RailsOtelContext
52
52
  end
53
53
 
54
54
  def on_finish(span)
55
+ return unless span.respond_to?(:attributes)
56
+
57
+ attrs = span.attributes
58
+ return unless attrs&.key?('db.system')
59
+
60
+ stash_if_prepare_span(span, attrs)
61
+
55
62
  return unless @slow_query_threshold_ms
56
- return unless span.respond_to?(:attributes) && span.attributes&.key?('db.system')
57
63
 
58
64
  start_ns = span.start_timestamp
59
65
  end_ns = span.end_timestamp
@@ -65,8 +71,8 @@ module RailsOtelContext
65
71
  # span.recording? is false here — the span has finished and current_span
66
72
  # has reverted to the HTTP parent. Write directly to the backing attributes
67
73
  # hash so db.slow lands on the actual DB span, not the HTTP parent.
68
- attrs = span.instance_variable_get(:@attributes)
69
- attrs.store(ActiveRecordContext::DB_SLOW_ATTR, true) if attrs.respond_to?(:store)
74
+ raw_attrs = span.instance_variable_get(:@attributes)
75
+ raw_attrs.store(ActiveRecordContext::DB_SLOW_ATTR, true) if raw_attrs.respond_to?(:store)
70
76
  rescue StandardError
71
77
  nil
72
78
  end
@@ -79,6 +85,17 @@ module RailsOtelContext
79
85
 
80
86
  private
81
87
 
88
+ # Stash PREPARE spans so Subscriber#start can retroactively apply AR context
89
+ # once the enclosing sql.active_record notification fires. PG's prepared-statement
90
+ # flow runs PREPARE → EXECUTE as separate wire operations; the PREPARE span
91
+ # finishes before the notification, so on_start never sees AR context for it.
92
+ def stash_if_prepare_span(span, attrs)
93
+ return unless attrs['db.operation'] == 'PREPARE'
94
+ return if attrs.key?('code.activerecord.model')
95
+
96
+ ActiveRecordContext.stash_prepare_span(span)
97
+ end
98
+
82
99
  def apply_call_context(span)
83
100
  # Explicit override: app code called FrameContext.with_frame (or Frameable).
84
101
  # O(1) — no stack walk. Takes priority over automatic detection.
@@ -4,6 +4,7 @@ module RailsOtelContext
4
4
  class Configuration
5
5
  attr_accessor :redis_source_enabled,
6
6
  :clickhouse_enabled,
7
+ :connection_pool_tracing_enabled,
7
8
  :span_name_formatter,
8
9
  :slow_query_threshold_ms
9
10
 
@@ -16,6 +17,7 @@ module RailsOtelContext
16
17
  def initialize
17
18
  @redis_source_enabled = false
18
19
  @clickhouse_enabled = true
20
+ @connection_pool_tracing_enabled = false
19
21
  @span_name_formatter = nil
20
22
  @custom_span_attributes = nil
21
23
  @request_context_enabled = false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsOtelContext
4
- VERSION = '0.9.7'
4
+ VERSION = '0.9.8'
5
5
  end
@@ -14,6 +14,7 @@ require 'rails_otel_context/adapters'
14
14
  require 'rails_otel_context/request_context'
15
15
  require 'rails_otel_context/frame_context'
16
16
  require 'rails_otel_context/call_context_processor'
17
+ require 'rails_otel_context/body_capture'
17
18
  require 'rails_otel_context/railtie' if defined?(Rails::Railtie)
18
19
 
19
20
  module RailsOtelContext
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.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Last9
@@ -66,10 +66,12 @@ files:
66
66
  - lib/rails_otel_context/activerecord_context.rb
67
67
  - lib/rails_otel_context/adapters.rb
68
68
  - lib/rails_otel_context/adapters/clickhouse.rb
69
+ - lib/rails_otel_context/adapters/connection_pool.rb
69
70
  - lib/rails_otel_context/adapters/mysql2.rb
70
71
  - lib/rails_otel_context/adapters/pg.rb
71
72
  - lib/rails_otel_context/adapters/redis.rb
72
73
  - lib/rails_otel_context/adapters/trilogy.rb
74
+ - lib/rails_otel_context/body_capture.rb
73
75
  - lib/rails_otel_context/call_context_processor.rb
74
76
  - lib/rails_otel_context/configuration.rb
75
77
  - lib/rails_otel_context/frame_context.rb