Module: Foam::Otel::Errors
- Defined in:
- lib/foam/otel/errors.rb
Overview
Backs the record_exception helper: records onto the active span a standard OTel exception event + ERROR status, deduped per span by exception object identity so recording the same exception twice produces ONE event. Recording an exception must never raise (BASE_PACKAGE_SPEC rule 9); recordException accepts customer error classes and never notifies any vendor tracker (section 0 traces row).
The seen-set lives ON the span object (an instance variable), not in a thread-local: a request span can be recorded on one thread and finished on another (ActionController::Live streams from a separate thread), so a thread-local would miss the dedupe across threads and leak entries. Span-carried state is GC'd with the span and travels with it.
Constant Summary collapse
- IVAR =
:@__foam_otel_recorded
Class Method Summary collapse
Class Method Details
.record_once(span, error) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/foam/otel/errors.rb', line 22 def record_once(span, error) return false unless span.respond_to?(:context) && span.context.valid? return false unless span.respond_to?(:recording?) && span.recording? return false unless error.is_a?(Exception) seen = span.instance_variable_get(IVAR) unless seen seen = [] span.instance_variable_set(IVAR, seen) end return false if seen.include?(error.object_id) seen << error.object_id span.record_exception(error) span.status = OpenTelemetry::Trace::Status.error(error..to_s) true rescue StandardError, SystemStackError # SystemStackError is not a StandardError: a customer error whose # #message/#to_s recurses unboundedly must never turn "recording an # exception" into a host-thread crash (rule 9). false end |