Class: RailsOtelContext::CallContextProcessor
- Inherits:
-
Object
- Object
- RailsOtelContext::CallContextProcessor
- Includes:
- SourceLocation
- Defined in:
- lib/rails_otel_context/call_context_processor.rb
Overview
SpanProcessor that enriches ALL spans with:
- code.namespace / code.function / code.filepath / code.lineno
(nearest app-code frame from the call stack — automatic, no manual setup)
- rails.controller / rails.action (when inside a controller action)
- rails.job (when inside a job)
Call-context resolution:
1. Explicit override — O(1). If app code calls FrameContext.with_frame (or
includes Frameable), that frame wins. Use this to intentionally override
the automatic nearest-frame (e.g., to expose a service boundary rather
than the inner repo it delegates to).
2. Stack walk — O(stack depth). Default path when no override is active.
DB adapters (Trilogy, PG, MySQL2, Redis, ClickHouse) additionally overwrite
code.* post-query from a shallower position, giving exact call-site precision.
rails.* attributes come from RequestContext (thread-local set by Railtie hooks) and are applied unconditionally — no config gate.
Custom attributes (configured via custom_span_attributes) are also applied. The callable must return a Hash (or nil) and must be fast — hot path per span.
Constant Summary collapse
- SPAN_CONTROLLER_ATTR =
'rails.controller'- SPAN_ACTION_ATTR =
'rails.action'- SPAN_JOB_ATTR =
'rails.job'- AR_MODEL_ATTR =
'code.activerecord.model'- AR_METHOD_ATTR =
'code.activerecord.method'- AR_SCOPE_ATTR =
'code.activerecord.scope'- AR_QUERY_COUNT_ATTR =
'db.query_count'- AR_ASYNC_ATTR =
'db.async'- ORIG_NAME_ATTR =
'l9.orig.name'
Instance Attribute Summary collapse
-
#app_root ⇒ Object
readonly
Exposed so SourceLocation mixin can use it for the stack-walk path.
Instance Method Summary collapse
-
#force_flush ⇒ Object
Return Export::SUCCESS (0) so the SDK’s tracer_provider.force_flush/shutdown can safely call results.max across all registered processors without raising ArgumentError when mixing our return value with integer status codes.
-
#initialize(app_root:, config: RailsOtelContext.configuration) ⇒ CallContextProcessor
constructor
A new instance of CallContextProcessor.
- #on_finish(span) ⇒ Object
- #on_start(span, _parent_context) ⇒ Object
- #shutdown ⇒ Object
Methods included from SourceLocation
#apply_call_site_to_span, #apply_source_to_span, #call_site_for_app, #source_location_for_app, #with_call_site_frame
Constructor Details
#initialize(app_root:, config: RailsOtelContext.configuration) ⇒ CallContextProcessor
Returns a new instance of CallContextProcessor.
40 41 42 43 44 45 |
# File 'lib/rails_otel_context/call_context_processor.rb', line 40 def initialize(app_root:, config: RailsOtelContext.configuration) @app_root = app_root.to_s @custom_span_attributes = config.custom_span_attributes @span_name_formatter = config.span_name_formatter @slow_query_threshold_ms = config.slow_query_threshold_ms end |
Instance Attribute Details
#app_root ⇒ Object (readonly)
Exposed so SourceLocation mixin can use it for the stack-walk path.
38 39 40 |
# File 'lib/rails_otel_context/call_context_processor.rb', line 38 def app_root @app_root end |
Instance Method Details
#force_flush ⇒ Object
Return Export::SUCCESS (0) so the SDK’s tracer_provider.force_flush/shutdown can safely call results.max across all registered processors without raising ArgumentError when mixing our return value with integer status codes.
83 |
# File 'lib/rails_otel_context/call_context_processor.rb', line 83 def force_flush(**) = 0 |
#on_finish(span) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/rails_otel_context/call_context_processor.rb', line 54 def on_finish(span) return unless span.respond_to?(:attributes) attrs = span.attributes return unless attrs&.key?('db.system') stash_if_prepare_span(span, attrs) return unless @slow_query_threshold_ms start_ns = span. end_ns = span. return unless start_ns && end_ns duration_ms = (end_ns - start_ns) / 1_000_000.0 return unless duration_ms >= @slow_query_threshold_ms # span.recording? is false here — the span has finished and current_span # has reverted to the HTTP parent. Write directly to the backing attributes # hash so db.slow lands on the actual DB span, not the HTTP parent. raw_attrs = span.instance_variable_get(:@attributes) raw_attrs.store(ActiveRecordContext::DB_SLOW_ATTR, true) if raw_attrs.respond_to?(:store) rescue StandardError nil end |
#on_start(span, _parent_context) ⇒ Object
47 48 49 50 51 52 |
# File 'lib/rails_otel_context/call_context_processor.rb', line 47 def on_start(span, _parent_context) apply_call_context(span) apply_request_context(span) apply_db_context(span) apply_custom_attributes(span) if @custom_span_attributes end |
#shutdown ⇒ Object
84 |
# File 'lib/rails_otel_context/call_context_processor.rb', line 84 def shutdown(**) = 0 |