Class: Bulldogger::Probe::Session
- Inherits:
-
Object
- Object
- Bulldogger::Probe::Session
- Defined in:
- lib/bulldogger/probe/session.rb
Overview
One probe run: resolves and reserves its targets, builds one TracePoint per target (contract-verbs.md: "1 TracePoint can only enable one target -- can't nest-enable a targeting TracePoint"), aggregates every observed call/return into MethodStats, and writes the evidence file on finish.
Class Method Summary collapse
Instance Method Summary collapse
- #enable! ⇒ Object
- #finish ⇒ Object
-
#initialize(targets:, config:, run:) ⇒ Session
constructor
A new instance of Session.
Constructor Details
#initialize(targets:, config:, run:) ⇒ Session
Returns a new instance of Session.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/bulldogger/probe/session.rb', line 62 def initialize(targets:, config:, run:) @targets = targets @config = config @run = run @redactor = Redactor.new(config.redact_patterns) @formatter = Formatter.new(config: config, redactor: @redactor) @stats = targets.each_with_object({}) do |target, hash| hash[target.label] = MethodStats.new(target: target, formatter: @formatter, redactor: @redactor, max_samples: config.max_samples) end @trace_points = [] @started_at = Time.now.utc @finished = false @finish_mutex = Mutex.new end |
Class Method Details
.run(target_strings, config:, run:) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/bulldogger/probe/session.rb', line 36 def self.run(target_strings, config:, run:) unless config.enabled # The switch being off must not stop the caller's own code # from running -- only from being observed and written. See # AGENTS.md: the tool must not change what the app does. yield if block_given? return nil end session = start(target_strings, config: config, run: run) # The written path comes from session.finish, not from # `begin...ensure...end`'s own value (that would be the # block's return value): an ensure clause's result is # discarded unless captured explicitly, and finish must still # run -- and its path still be returned -- when the block # raises, since a probed run that hit an exception is exactly # the case where the evidence is most worth having. result = nil begin yield ensure result = session.finish end result end |
.start(target_strings, config:, run:) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/bulldogger/probe/session.rb', line 17 def self.start(target_strings, config:, run:) return nil unless config.enabled targets = TargetResolver.resolve!(target_strings) labels = targets.map(&:label) Registry.reserve!(labels) begin new(targets: targets, config: config, run: run).enable! rescue Exception # rubocop:disable Lint/RescueException # A target that fails mid-enable (all targets already passed # TargetResolver's own check, so this is the unlikely case -- # a race with the app redefining a method, say) must not # leave its label stuck in Registry: that would refuse every # later probe of the same target for the rest of the process. Registry.release(labels) raise end end |
Instance Method Details
#enable! ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/bulldogger/probe/session.rb', line 78 def enable! RaiseTracker.instance.acquire @targets.each do |target| tp = build_trace_point(@stats[target.label]) tp.enable(target: target.unbound_method) @trace_points << tp end self rescue Exception # rubocop:disable Lint/RescueException @trace_points.each(&:disable) RaiseTracker.instance.release raise end |
#finish ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/bulldogger/probe/session.rb', line 92 def finish @finish_mutex.synchronize do return @result_path if @finished @finished = true @trace_points.each(&:disable) RaiseTracker.instance.release Registry.release(@targets.map(&:label)) @result_path = Writer.write(run: @run, config: @config, targets: @targets, stats: @stats, started_at: @started_at) end end |