Class: FiberAudit::Runtime::Probes::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/fiber_audit/runtime/probes/base.rb

Overview

Shared behavior-preserving observation boundary for targeted wrappers. rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: Observation

Constant Summary collapse

SOURCE =
:targeted_probe
MAX_CALLSITE_FRAMES =
32
INTERNAL_PATH =
File.expand_path('../..', __dir__).freeze
ORIGINAL_MUTEX_SYNCHRONIZE =
Mutex.instance_method(:synchronize)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(recorder:, clock:, redactor:, active_operations:, execution_context_store: nil, pid_source: Process.method(:pid)) ⇒ Base

Returns a new instance of Base.



37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/fiber_audit/runtime/probes/base.rb', line 37

def initialize(recorder:, clock:, redactor:, active_operations:, execution_context_store: nil,
               pid_source: Process.method(:pid))
  validate_dependencies!(recorder, clock, redactor, active_operations, execution_context_store, pid_source)
  @recorder = recorder
  @clock = clock
  @redactor = redactor
  @active_operations = active_operations
  @execution_context_store = execution_context_store
  @pid_source = pid_source
  @owner_pid = current_pid
  @active = true
end

Instance Attribute Details

#active_operationsObject (readonly)

Returns the value of attribute active_operations.



35
36
37
# File 'lib/fiber_audit/runtime/probes/base.rb', line 35

def active_operations
  @active_operations
end

#clockObject (readonly)

Returns the value of attribute clock.



35
36
37
# File 'lib/fiber_audit/runtime/probes/base.rb', line 35

def clock
  @clock
end

#execution_context_storeObject (readonly)

Returns the value of attribute execution_context_store.



35
36
37
# File 'lib/fiber_audit/runtime/probes/base.rb', line 35

def execution_context_store
  @execution_context_store
end

#owner_pidObject (readonly)

Returns the value of attribute owner_pid.



35
36
37
# File 'lib/fiber_audit/runtime/probes/base.rb', line 35

def owner_pid
  @owner_pid
end

#recorderObject (readonly)

Returns the value of attribute recorder.



35
36
37
# File 'lib/fiber_audit/runtime/probes/base.rb', line 35

def recorder
  @recorder
end

#redactorObject (readonly)

Returns the value of attribute redactor.



35
36
37
# File 'lib/fiber_audit/runtime/probes/base.rb', line 35

def redactor
  @redactor
end

Class Method Details

.enter_guardObject



300
301
302
303
304
305
306
307
# File 'lib/fiber_audit/runtime/probes/base.rb', line 300

def enter_guard
  state = guard_state
  key = guard_key
  ORIGINAL_MUTEX_SYNCHRONIZE.bind_call(state.fetch(:mutex)) do
    depths = state.fetch(:depths)
    depths[key] = depths.fetch(key, 0) + 1
  end
end

.exit_guardObject



309
310
311
312
313
314
315
316
317
# File 'lib/fiber_audit/runtime/probes/base.rb', line 309

def exit_guard
  state = guard_state
  key = guard_key
  ORIGINAL_MUTEX_SYNCHRONIZE.bind_call(state.fetch(:mutex)) do
    depths = state.fetch(:depths)
    depth = depths.fetch(key, 1) - 1
    depth.positive? ? depths[key] = depth : depths.delete(key)
  end
end

.guarded?Boolean

Returns:

  • (Boolean)


292
293
294
295
296
297
298
# File 'lib/fiber_audit/runtime/probes/base.rb', line 292

def guarded?
  state = guard_state
  key = guard_key
  ORIGINAL_MUTEX_SYNCHRONIZE.bind_call(state.fetch(:mutex)) do
    state.fetch(:depths).fetch(key, 0).positive?
  end
end

Instance Method Details

#active_for_current_process?Boolean

Returns:

  • (Boolean)


85
86
87
88
89
# File 'lib/fiber_audit/runtime/probes/base.rb', line 85

def active_for_current_process?
  @active && owner_pid == current_pid
rescue StandardError
  false
end

#deactivateObject



80
81
82
83
# File 'lib/fiber_audit/runtime/probes/base.rb', line 80

def deactivate
  @active = false
  self
end

#fail_open?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/fiber_audit/runtime/probes/base.rb', line 91

def fail_open?
  recorder.session.policy.fail_open?
end

#instrumentation_failure(error) ⇒ Object



95
96
97
98
99
100
# File 'lib/fiber_audit/runtime/probes/base.rb', line 95

def instrumentation_failure(error)
  
  raise error unless fail_open?

  nil
end

#observe(operation:, measurements: {}, emit_start: false, measurement_builder: nil) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/fiber_audit/runtime/probes/base.rb', line 50

def observe(operation:, measurements: {}, emit_start: false, measurement_builder: nil)
  return yield unless active_for_current_process?
  return yield if guarded?

  observation = begin
    prepare_observation(operation, measurements)
  rescue StandardError => e
    instrumentation_failure(e)
  end
  return yield unless observation

  with_guard { emit_start_observation(observation) } if emit_start
  completed = false
  result = nil
  begin
    result = yield
    completed = true
    result
  ensure
    finalize_observation(observation, completed: completed, result: result, measurement_builder: measurement_builder)
  end
end

#with_guardObject



73
74
75
76
77
78
# File 'lib/fiber_audit/runtime/probes/base.rb', line 73

def with_guard
  self.class.enter_guard
  yield
ensure
  self.class.exit_guard
end