Class: Foam::Otel::PayloadCapture::BodyAccumulator
- Inherits:
-
Object
- Object
- Foam::Otel::PayloadCapture::BodyAccumulator
- Defined in:
- lib/foam/otel/payload_capture.rb
Overview
Bounded, defensive accumulation shared by both directions. Tracks a stream POSITION and a HIGH-WATER mark so a reposition + re-read (the Rack::MethodOverride shape: an outer middleware reads the form body, rewinds, and the framework re-reads it) never double-captures or double-counts — only bytes beyond the high-water mark are new. The raw buffer is binary and hard-capped; text is scrubbed to valid UTF-8 and cap-cut only at snapshot time.
Instance Method Summary collapse
-
#bytes ⇒ Object
The true byte count observed (the high-water mark: rewound re-reads never inflate it).
-
#initialize(capture_text:) ⇒ BodyAccumulator
constructor
A new instance of BodyAccumulator.
-
#note_position(new_pos) ⇒ Object
A reposition on the underlying stream (rewind / seek / pos=): track the new position so a re-read never double-captures or double-counts.
- #observe(chunk) ⇒ Object
- #saw_data? ⇒ Boolean
-
#snapshot ⇒ Object
The captured text — scrubbed to valid UTF-8, cut at MAX_CAPTURED_BODY_CHARS with the fleet truncation marker — or nil when text capture is off or nothing was seen.
Constructor Details
#initialize(capture_text:) ⇒ BodyAccumulator
Returns a new instance of BodyAccumulator.
427 428 429 430 431 |
# File 'lib/foam/otel/payload_capture.rb', line 427 def initialize(capture_text:) @buffer = capture_text ? String.new(encoding: Encoding::BINARY) : nil @pos = 0 @high_water = 0 end |
Instance Method Details
#bytes ⇒ Object
The true byte count observed (the high-water mark: rewound re-reads never inflate it).
471 472 473 |
# File 'lib/foam/otel/payload_capture.rb', line 471 def bytes @high_water end |
#note_position(new_pos) ⇒ Object
A reposition on the underlying stream (rewind / seek / pos=): track the new position so a re-read never double-captures or double-counts. Anything non-sensical degrades to 0 — the rewind-equivalent — which can only UNDER-position (bytes below the high-water mark are never appended twice; rule 9 direction).
461 462 463 |
# File 'lib/foam/otel/payload_capture.rb', line 461 def note_position(new_pos) @pos = new_pos.is_a?(Integer) && new_pos >= 0 ? new_pos : 0 end |
#observe(chunk) ⇒ Object
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
# File 'lib/foam/otel/payload_capture.rb', line 433 def observe(chunk) return unless chunk.is_a?(String) size = chunk.bytesize return if size.zero? new_pos = @pos + size if new_pos > @high_water # Never more than the chunk itself: a forward seek past the # high-water mark makes the positional gap look "fresh", but the # skipped bytes were never observed — only the chunk's own tail # is appendable (the high-water mark still advances to the true # stream position, so re-reads after it stay deduped). fresh = [new_pos - @high_water, size].min append(chunk.byteslice(size - fresh, fresh)) @high_water = new_pos end @pos = new_pos nil rescue StandardError, SystemStackError nil end |
#saw_data? ⇒ Boolean
465 466 467 |
# File 'lib/foam/otel/payload_capture.rb', line 465 def saw_data? @high_water.positive? end |
#snapshot ⇒ Object
The captured text — scrubbed to valid UTF-8, cut at MAX_CAPTURED_BODY_CHARS with the fleet truncation marker — or nil when text capture is off or nothing was seen.
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
# File 'lib/foam/otel/payload_capture.rb', line 478 def snapshot return nil if @buffer.nil? || !saw_data? text = Redaction.scrub_utf8(@buffer.dup) return nil unless text.is_a?(String) && !text.empty? if text.length > MAX_CAPTURED_BODY_CHARS text[0, MAX_CAPTURED_BODY_CHARS] + TRUNCATION_MARKER elsif @high_water > @buffer.bytesize text + TRUNCATION_MARKER # bytes beyond the buffer cap were observed else text end rescue StandardError, SystemStackError nil end |