Class: OrangeTap::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/orange_tap/session.rb

Overview

Controls a single recording session's lifecycle. Each #open call creates a dedicated Queue and Worker Thread; there is no session_id, because the Queue instance itself is what scopes events to this session. This also makes concurrent sessions (multiple Session instances open at once) work without any cross-session bookkeeping: each has its own Queue, Thread, and TracePoint set.

Instance Method Summary collapse

Constructor Details

#initialize(registry: OrangeTap.default_registry, config: OrangeTap.config) ⇒ Session

Returns a new instance of Session.



13
14
15
16
17
18
19
# File 'lib/orange_tap/session.rb', line 13

def initialize(registry: OrangeTap.default_registry, config: OrangeTap.config)
  @registry = registry
  @config = config
  @queue = nil
  @worker_thread = nil
  @tracepoint_targets = nil
end

Instance Method Details

#openObject

Raises:



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/orange_tap/session.rb', line 21

def open
  raise AlreadyOpenError if @queue

  # Anchor monotonic time to wall-clock time once, at session start, so
  # OtelConverter can later translate CLOCK_MONOTONIC-based timestamps
  # (cheap, used inside the hot hook) into absolute OTLP unix ns.
  start_mono_ns = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
  start_unix_ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
  trace_id = SecureRandom.hex(16)

  @queue = Thread::Queue.new

  # One TracePoint per target ISeq: whether a single TracePoint can
  # safely enable(target:) more than one ISeq is version-dependent, so
  # each ISeq gets its own TracePoint instance to enable/disable.
  @tracepoint_targets = @registry.targets.map { |iseq| [build_tracepoint(@queue), iseq] }

  ctx = Worker::Context.new(
    queue: @queue, config: @config, trace_id: trace_id,
    start_mono_ns: start_mono_ns, start_unix_ns: start_unix_ns
  )
  @worker_thread = Thread.new(ctx) { |worker_ctx| Worker.new(worker_ctx).run }

  @tracepoint_targets.each { |tp, iseq| tp.enable(target: iseq) }
  self
end

#stopObject

Raises:



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/orange_tap/session.rb', line 48

def stop
  raise NotOpenError unless @queue

  # Disable hooks before closing the queue / waiting on the worker, so
  # that even if the worker raises, tracing has already stopped and
  # cannot leak into whatever runs next.
  @tracepoint_targets.each { |tp, _iseq| tp.disable }
  @queue.close
  path = @worker_thread.value
  @queue = nil
  @tracepoint_targets = nil
  @worker_thread = nil
  path
end