Class: Sashiko::Ractor::Recorder

Inherits:
Object
  • Object
show all
Defined in:
lib/sashiko/ractor.rb

Overview

In-Ractor recorder that collects SpanEvents. One instance per worker Ractor, accessed via Recorder.current (thread-local inside the Ractor).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRecorder

Take a wall-clock anchor once at recorder construction, then drive all per-span timestamps from the monotonic clock relative to that anchor. This gives OTel the wall-clock timestamps it expects while keeping span durations immune to NTP / system-time jumps that hit mid-batch.



34
35
36
37
38
39
40
# File 'lib/sashiko/ractor.rb', line 34

def initialize
  @events       = [] #: Array[SpanEvent]
  @stack        = [] #: Array[Integer]
  @next_id      = 0
  @wall_anchor  = Process.clock_gettime(Process::CLOCK_REALTIME,  :nanosecond)
  @mono_anchor  = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
end

Instance Attribute Details

#eventsObject (readonly)

Returns the value of attribute events.



42
43
44
# File 'lib/sashiko/ractor.rb', line 42

def events
  @events
end

Class Method Details

.currentObject



67
# File 'lib/sashiko/ractor.rb', line 67

def self.current = ::Thread.current[:sashiko_recorder] ||= new

.drain_events!Object



69
70
71
72
73
74
75
# File 'lib/sashiko/ractor.rb', line 69

def self.drain_events!
  r = ::Thread.current[:sashiko_recorder]
  ::Thread.current[:sashiko_recorder] = nil
  empty = [] #: Array[SpanEvent]
  events = r ? r.events : empty
  events.map { |e| ::Ractor.make_shareable(e) }.freeze
end

.install(recorder) ⇒ Object



68
# File 'lib/sashiko/ractor.rb', line 68

def self.install(recorder) = ::Thread.current[:sashiko_recorder] = recorder

Instance Method Details

#span(name, kind: :internal, attributes: nil) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/sashiko/ractor.rb', line 44

def span(name, kind: :internal, attributes: nil)
  id = (@next_id += 1)
  parent_id = @stack.last
  start_ns = now_ns
  @stack.push(id)
  error = nil
  begin
    result = block_given? ? yield : nil
  rescue => e
    error = e.message
    raise
  ensure
    @events << SpanEvent.new(
      id:, parent_id:, name:, kind:,
      attributes: deep_freeze(attributes || {}),
      start_ns:, end_ns: now_ns,
      status_error: error,
    )
    @stack.pop
  end
  result
end