Class: OpenTrace::RequestBuffer
- Inherits:
-
Object
- Object
- OpenTrace::RequestBuffer
- Defined in:
- lib/opentrace/request_buffer.rb
Constant Summary collapse
- CAPTURE_LEVELS =
Capture levels control how much data is included in the final document. :minimal — request identity + timing only (no bodies, no captures) :standard — includes captures but strips request/response bodies :full — everything
%i[minimal standard full].freeze
- CAPTURE_LEVEL_RANK =
{ none: -1, minimal: 0, standard: 1, full: 2 }.freeze
- DOMAINS =
Domains that can have individual capture-level overrides
%i[request sql http email file audit log timeline].freeze
- BASE_BYTE_ESTIMATE =
1KB base overhead
1024
Instance Attribute Summary collapse
-
#action ⇒ Object
Context fields (set by middleware).
-
#audit_captures ⇒ Object
readonly
Read-only access to internal capture arrays (useful for tests/inspection).
-
#content_type ⇒ Object
Request/response fields (set by middleware).
-
#context ⇒ Object
Context fields (set by middleware).
-
#controller ⇒ Object
Context fields (set by middleware).
-
#cookies ⇒ Object
Request/response fields (set by middleware).
-
#email_captures ⇒ Object
readonly
Read-only access to internal capture arrays (useful for tests/inspection).
-
#event_type ⇒ Object
Returns the value of attribute event_type.
-
#file_captures ⇒ Object
readonly
Read-only access to internal capture arrays (useful for tests/inspection).
-
#http_captures ⇒ Object
readonly
Read-only access to internal capture arrays (useful for tests/inspection).
-
#id ⇒ Object
Returns the value of attribute id.
-
#ip_address ⇒ Object
Request/response fields (set by middleware).
-
#job_arguments ⇒ Object
Job fields (for job.perform).
-
#job_class ⇒ Object
Job fields (for job.perform).
-
#job_enqueued_at ⇒ Object
Job fields (for job.perform).
-
#job_executions ⇒ Object
Job fields (for job.perform).
-
#job_id ⇒ Object
Job fields (for job.perform).
-
#job_queue ⇒ Object
Job fields (for job.perform).
-
#job_queue_latency_ms ⇒ Object
Job fields (for job.perform).
-
#logs ⇒ Object
readonly
Read-only access to internal capture arrays (useful for tests/inspection).
-
#memory_after ⇒ Object
Performance fields (set by middleware).
-
#memory_before ⇒ Object
Performance fields (set by middleware).
-
#parent_span_id ⇒ Object
Context fields (set by middleware).
-
#referer ⇒ Object
Request/response fields (set by middleware).
-
#request_body ⇒ Object
Request/response fields (set by middleware).
-
#request_headers ⇒ Object
Request/response fields (set by middleware).
-
#request_id ⇒ Object
Context fields (set by middleware).
-
#request_method ⇒ Object
Request/response fields (set by middleware).
-
#request_params ⇒ Object
Request/response fields (set by middleware).
-
#request_path ⇒ Object
Request/response fields (set by middleware).
-
#request_size ⇒ Object
Request/response fields (set by middleware).
-
#response_body ⇒ Object
Request/response fields (set by middleware).
-
#response_headers ⇒ Object
Request/response fields (set by middleware).
-
#response_size ⇒ Object
Request/response fields (set by middleware).
-
#response_status ⇒ Object
Request/response fields (set by middleware).
-
#session_data ⇒ Object
Request/response fields (set by middleware).
-
#span_id ⇒ Object
Context fields (set by middleware).
-
#sql_captures ⇒ Object
readonly
Read-only access to internal capture arrays (useful for tests/inspection).
-
#started_at ⇒ Object
Returns the value of attribute started_at.
-
#timeline ⇒ Object
readonly
Read-only access to internal capture arrays (useful for tests/inspection).
-
#trace_id ⇒ Object
Context fields (set by middleware).
-
#triggered_by_job_id ⇒ Object
Job fields (for job.perform).
-
#triggered_by_request_id ⇒ Object
Job fields (for job.perform).
-
#user_agent ⇒ Object
Request/response fields (set by middleware).
Instance Method Summary collapse
- #audit_truncated? ⇒ Boolean
-
#byte_size ⇒ Object
── Output ──.
- #exceeded_buffer? ⇒ Boolean
-
#initialize(max_buffer_bytes: 1_048_576, max_audit_events: 50) ⇒ RequestBuffer
constructor
A new instance of RequestBuffer.
- #record_audit(action:, record_type:, record_id: nil, actor_id: nil, actor_type: nil, changed_fields: nil, full_before: nil, full_after: nil) ⇒ Object
- #record_email(mailer_class:, mailer_action:, from: nil, to: nil, subject: nil, body_html: nil, body_text: nil, template: nil, variables: nil, attachments: nil, delivery_status: nil, smtp_response: nil, duration_ms: nil) ⇒ Object
- #record_file(action:, filename:, size_bytes: nil, content_type: nil, service: nil, key: nil, duration_ms: nil) ⇒ Object
- #record_http(method:, url:, host: nil, vendor: nil, status: nil, duration_ms:, request_headers: nil, request_body: nil, response_headers: nil, response_body: nil, response_size: nil, retry_attempt: nil, error_class: nil) ⇒ Object
- #record_log(level:, message:, metadata: nil) ⇒ Object
-
#record_sql(raw_sql:, normalized_sql: nil, binds: nil, duration_ms:, name: nil, cached: false, row_count: nil, in_transaction: false, fingerprint: nil, table: nil, caller_location: nil) ⇒ Object
── Accumulation methods (called by subscribers during request) ──.
- #record_timeline(type:, name:, duration_ms: nil, extra: {}) ⇒ Object
-
#reset! ⇒ Object
── Lifecycle ──.
- #to_document(capture_level:, domain_overrides: {}) ⇒ Object
Constructor Details
#initialize(max_buffer_bytes: 1_048_576, max_audit_events: 50) ⇒ RequestBuffer
Returns a new instance of RequestBuffer.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/opentrace/request_buffer.rb', line 43 def initialize(max_buffer_bytes: 1_048_576, max_audit_events: 50) @max_buffer_bytes = max_buffer_bytes @max_audit_events = max_audit_events # Pre-allocate arrays (reused across checkouts via reset!) @sql_captures = [] @http_captures = [] @email_captures = [] @file_captures = [] @audit_captures = [] @logs = [] @timeline = [] @audit_truncated = false # Identity — set on checkout @id = nil @started_at = nil @event_type = nil # All other fields start nil reset_fields! end |
Instance Attribute Details
#action ⇒ Object
Context fields (set by middleware)
31 32 33 |
# File 'lib/opentrace/request_buffer.rb', line 31 def action @action end |
#audit_captures ⇒ Object (readonly)
Read-only access to internal capture arrays (useful for tests/inspection)
40 41 42 |
# File 'lib/opentrace/request_buffer.rb', line 40 def audit_captures @audit_captures end |
#content_type ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def content_type @content_type end |
#context ⇒ Object
Context fields (set by middleware)
31 32 33 |
# File 'lib/opentrace/request_buffer.rb', line 31 def context @context end |
#controller ⇒ Object
Context fields (set by middleware)
31 32 33 |
# File 'lib/opentrace/request_buffer.rb', line 31 def controller @controller end |
#cookies ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def @cookies end |
#email_captures ⇒ Object (readonly)
Read-only access to internal capture arrays (useful for tests/inspection)
40 41 42 |
# File 'lib/opentrace/request_buffer.rb', line 40 def email_captures @email_captures end |
#event_type ⇒ Object
Returns the value of attribute event_type.
19 20 21 |
# File 'lib/opentrace/request_buffer.rb', line 19 def event_type @event_type end |
#file_captures ⇒ Object (readonly)
Read-only access to internal capture arrays (useful for tests/inspection)
40 41 42 |
# File 'lib/opentrace/request_buffer.rb', line 40 def file_captures @file_captures end |
#http_captures ⇒ Object (readonly)
Read-only access to internal capture arrays (useful for tests/inspection)
40 41 42 |
# File 'lib/opentrace/request_buffer.rb', line 40 def http_captures @http_captures end |
#id ⇒ Object
Returns the value of attribute id.
19 20 21 |
# File 'lib/opentrace/request_buffer.rb', line 19 def id @id end |
#ip_address ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def ip_address @ip_address end |
#job_arguments ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def job_arguments @job_arguments end |
#job_class ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def job_class @job_class end |
#job_enqueued_at ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def job_enqueued_at @job_enqueued_at end |
#job_executions ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def job_executions @job_executions end |
#job_id ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def job_id @job_id end |
#job_queue ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def job_queue @job_queue end |
#job_queue_latency_ms ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def job_queue_latency_ms @job_queue_latency_ms end |
#logs ⇒ Object (readonly)
Read-only access to internal capture arrays (useful for tests/inspection)
40 41 42 |
# File 'lib/opentrace/request_buffer.rb', line 40 def logs @logs end |
#memory_after ⇒ Object
Performance fields (set by middleware)
28 29 30 |
# File 'lib/opentrace/request_buffer.rb', line 28 def memory_after @memory_after end |
#memory_before ⇒ Object
Performance fields (set by middleware)
28 29 30 |
# File 'lib/opentrace/request_buffer.rb', line 28 def memory_before @memory_before end |
#parent_span_id ⇒ Object
Context fields (set by middleware)
31 32 33 |
# File 'lib/opentrace/request_buffer.rb', line 31 def parent_span_id @parent_span_id end |
#referer ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def referer @referer end |
#request_body ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def request_body @request_body end |
#request_headers ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def request_headers @request_headers end |
#request_id ⇒ Object
Context fields (set by middleware)
31 32 33 |
# File 'lib/opentrace/request_buffer.rb', line 31 def request_id @request_id end |
#request_method ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def request_method @request_method end |
#request_params ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def request_params @request_params end |
#request_path ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def request_path @request_path end |
#request_size ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def request_size @request_size end |
#response_body ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def response_body @response_body end |
#response_headers ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def response_headers @response_headers end |
#response_size ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def response_size @response_size end |
#response_status ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def response_status @response_status end |
#session_data ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def session_data @session_data end |
#span_id ⇒ Object
Context fields (set by middleware)
31 32 33 |
# File 'lib/opentrace/request_buffer.rb', line 31 def span_id @span_id end |
#sql_captures ⇒ Object (readonly)
Read-only access to internal capture arrays (useful for tests/inspection)
40 41 42 |
# File 'lib/opentrace/request_buffer.rb', line 40 def sql_captures @sql_captures end |
#started_at ⇒ Object
Returns the value of attribute started_at.
19 20 21 |
# File 'lib/opentrace/request_buffer.rb', line 19 def started_at @started_at end |
#timeline ⇒ Object (readonly)
Read-only access to internal capture arrays (useful for tests/inspection)
40 41 42 |
# File 'lib/opentrace/request_buffer.rb', line 40 def timeline @timeline end |
#trace_id ⇒ Object
Context fields (set by middleware)
31 32 33 |
# File 'lib/opentrace/request_buffer.rb', line 31 def trace_id @trace_id end |
#triggered_by_job_id ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def triggered_by_job_id @triggered_by_job_id end |
#triggered_by_request_id ⇒ Object
Job fields (for job.perform)
35 36 37 |
# File 'lib/opentrace/request_buffer.rb', line 35 def triggered_by_request_id @triggered_by_request_id end |
#user_agent ⇒ Object
Request/response fields (set by middleware)
22 23 24 |
# File 'lib/opentrace/request_buffer.rb', line 22 def user_agent @user_agent end |
Instance Method Details
#audit_truncated? ⇒ Boolean
221 222 223 |
# File 'lib/opentrace/request_buffer.rb', line 221 def audit_truncated? @audit_truncated end |
#byte_size ⇒ Object
── Output ──
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/opentrace/request_buffer.rb', line 190 def byte_size size = BASE_BYTE_ESTIMATE size += @request_body.bytesize if @request_body.is_a?(String) size += @response_body.bytesize if @response_body.is_a?(String) @sql_captures.each do |c| size += c[:raw_sql].bytesize if c[:raw_sql].is_a?(String) end @http_captures.each do |c| size += c[:request_body].bytesize if c[:request_body].is_a?(String) size += c[:response_body].bytesize if c[:response_body].is_a?(String) end @email_captures.each do |c| size += c[:body_html].bytesize if c[:body_html].is_a?(String) size += c[:body_text].bytesize if c[:body_text].is_a?(String) end @logs.each do |c| size += c[:message].bytesize if c[:message].is_a?(String) end size end |
#exceeded_buffer? ⇒ Boolean
217 218 219 |
# File 'lib/opentrace/request_buffer.rb', line 217 def exceeded_buffer? byte_size > @max_buffer_bytes end |
#record_audit(action:, record_type:, record_id: nil, actor_id: nil, actor_type: nil, changed_fields: nil, full_before: nil, full_after: nil) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/opentrace/request_buffer.rb', line 142 def record_audit(action:, record_type:, record_id: nil, actor_id: nil, actor_type: nil, changed_fields: nil, full_before: nil, full_after: nil) if @audit_captures.size >= @max_audit_events @audit_truncated = true return end @audit_captures << { action: action, record_type: record_type, record_id: record_id, actor_id: actor_id, actor_type: actor_type, changed_fields: changed_fields, full_before: full_before, full_after: full_after } end |
#record_email(mailer_class:, mailer_action:, from: nil, to: nil, subject: nil, body_html: nil, body_text: nil, template: nil, variables: nil, attachments: nil, delivery_status: nil, smtp_response: nil, duration_ms: nil) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/opentrace/request_buffer.rb', line 108 def record_email(mailer_class:, mailer_action:, from: nil, to: nil, subject: nil, body_html: nil, body_text: nil, template: nil, variables: nil, attachments: nil, delivery_status: nil, smtp_response: nil, duration_ms: nil) @email_captures << { mailer_class: mailer_class, mailer_action: mailer_action, from: from, to: to, subject: subject, body_html: body_html, body_text: body_text, template: template, variables: variables, attachments: , delivery_status: delivery_status, smtp_response: smtp_response, duration_ms: duration_ms } end |
#record_file(action:, filename:, size_bytes: nil, content_type: nil, service: nil, key: nil, duration_ms: nil) ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/opentrace/request_buffer.rb', line 129 def record_file(action:, filename:, size_bytes: nil, content_type: nil, service: nil, key: nil, duration_ms: nil) @file_captures << { action: action, filename: filename, size_bytes: size_bytes, content_type: content_type, service: service, key: key, duration_ms: duration_ms } end |
#record_http(method:, url:, host: nil, vendor: nil, status: nil, duration_ms:, request_headers: nil, request_body: nil, response_headers: nil, response_body: nil, response_size: nil, retry_attempt: nil, error_class: nil) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/opentrace/request_buffer.rb', line 87 def record_http(method:, url:, host: nil, vendor: nil, status: nil, duration_ms:, request_headers: nil, request_body: nil, response_headers: nil, response_body: nil, response_size: nil, retry_attempt: nil, error_class: nil) @http_captures << { method: method, url: url, host: host, vendor: vendor, status: status, duration_ms: duration_ms, request_headers: request_headers, request_body: request_body, response_headers: response_headers, response_body: response_body, response_size: response_size, retry_attempt: retry_attempt, error_class: error_class } end |
#record_log(level:, message:, metadata: nil) ⇒ Object
162 163 164 165 166 167 168 |
# File 'lib/opentrace/request_buffer.rb', line 162 def record_log(level:, message:, metadata: nil) @logs << { level: level, message: , metadata: } end |
#record_sql(raw_sql:, normalized_sql: nil, binds: nil, duration_ms:, name: nil, cached: false, row_count: nil, in_transaction: false, fingerprint: nil, table: nil, caller_location: nil) ⇒ Object
── Accumulation methods (called by subscribers during request) ──
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/opentrace/request_buffer.rb', line 69 def record_sql(raw_sql:, normalized_sql: nil, binds: nil, duration_ms:, name: nil, cached: false, row_count: nil, in_transaction: false, fingerprint: nil, table: nil, caller_location: nil) @sql_captures << { raw_sql: raw_sql, normalized_sql: normalized_sql, binds: binds, duration_ms: duration_ms, name: name, cached: cached, row_count: row_count, in_transaction: in_transaction, fingerprint: fingerprint, table: table, caller_location: caller_location } end |
#record_timeline(type:, name:, duration_ms: nil, extra: {}) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/opentrace/request_buffer.rb', line 170 def record_timeline(type:, name:, duration_ms: nil, extra: {}) offset = if @started_at ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started_at) * 1000).round(1) else 0.0 end entry = { type: type, name: name, offset_ms: offset } entry[:duration_ms] = duration_ms if duration_ms entry.merge!(extra) unless extra.empty? @timeline << entry end |
#reset! ⇒ Object
── Lifecycle ──
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/opentrace/request_buffer.rb', line 296 def reset! @id = nil @started_at = nil @event_type = nil # Clear arrays but keep allocated memory @sql_captures.clear @http_captures.clear @email_captures.clear @file_captures.clear @audit_captures.clear @logs.clear @timeline.clear @audit_truncated = false reset_fields! end |
#to_document(capture_level:, domain_overrides: {}) ⇒ Object
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/opentrace/request_buffer.rb', line 225 def to_document(capture_level:, domain_overrides: {}) base_rank = CAPTURE_LEVEL_RANK.fetch(capture_level, 1) doc = {} # Identity doc[:id] = @id doc[:event_type] = @event_type doc[:started_at] = @started_at # Request identity (always included) doc[:request] = build_request_section(base_rank, domain_overrides) # Response (always included at minimum level for status) doc[:response] = build_response_section(base_rank, domain_overrides) # Context doc[:context] = @context if @context # Controller/action doc[:controller] = @controller if @controller doc[:action] = @action if @action # Tracing doc[:request_id] = @request_id if @request_id doc[:trace_id] = @trace_id if @trace_id doc[:span_id] = @span_id if @span_id doc[:parent_span_id] = @parent_span_id if @parent_span_id # Performance if @memory_before || @memory_after doc[:performance] = { memory_before: @memory_before, memory_after: @memory_after }.compact end # Job fields if @job_class doc[:job] = { class: @job_class, id: @job_id, queue: @job_queue, arguments: @job_arguments, executions: @job_executions, queue_latency_ms: @job_queue_latency_ms, enqueued_at: @job_enqueued_at, triggered_by_request_id: @triggered_by_request_id, triggered_by_job_id: @triggered_by_job_id }.compact end # Domain captures — only include if above :minimal unless base_rank == 0 && !has_domain_override?(domain_overrides) doc[:sql] = filter_captures(@sql_captures, :sql, base_rank, domain_overrides) unless @sql_captures.empty? && !domain_included?(:sql, base_rank, domain_overrides) doc[:http] = filter_captures(@http_captures, :http, base_rank, domain_overrides) unless @http_captures.empty? && !domain_included?(:http, base_rank, domain_overrides) doc[:email] = filter_captures(@email_captures, :email, base_rank, domain_overrides) unless @email_captures.empty? && !domain_included?(:email, base_rank, domain_overrides) doc[:file] = filter_captures(@file_captures, :file, base_rank, domain_overrides) unless @file_captures.empty? && !domain_included?(:file, base_rank, domain_overrides) doc[:audit] = filter_captures(@audit_captures, :audit, base_rank, domain_overrides) unless @audit_captures.empty? && !domain_included?(:audit, base_rank, domain_overrides) doc[:logs] = filter_captures(@logs, :log, base_rank, domain_overrides) unless @logs.empty? && !domain_included?(:log, base_rank, domain_overrides) doc[:timeline] = @timeline.dup unless @timeline.empty? end doc[:audit_truncated] = true if @audit_truncated doc[:buffer_exceeded] = true if exceeded_buffer? doc.compact end |