Class: Bulldogger::Record::Writer

Inherits:
Object
  • Object
show all
Defined in:
lib/bulldogger/record/writer.rb

Overview

Appends one JSON object per line to trace-NNN.jsonl, plus a header line written once at construction.

The NNN is picked by scanning the run directory for existing trace-*.jsonl files, not an in-memory counter: Run (owned elsewhere) already hands out its own NNN-slug.json sequence for evidence files, and a Record session has no access to that counter -- nor should it share one, since "trace-NNN" and "NNN-slug" are different filename shapes with no shared meaning to a reader comparing NNN values across them.

Constant Summary collapse

FILENAME_PATTERN =
/\Atrace-(\d+)\.jsonl\z/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(run_dir:, header:) ⇒ Writer

Returns a new instance of Writer.



25
26
27
28
29
# File 'lib/bulldogger/record/writer.rb', line 25

def initialize(run_dir:, header:)
  @path = self.class.reserve_path(run_dir)
  @io = File.open(@path, "w")
  write_line(header)
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



23
24
25
# File 'lib/bulldogger/record/writer.rb', line 23

def path
  @path
end

Class Method Details

.reserve_path(run_dir) ⇒ Object

Reserves the next trace-NNN.jsonl name under a process-wide lock. Two sessions starting back to back (or on two threads) must never both see the same "no trace-*.jsonl yet" listing and pick the same NNN, so the file is created (empty) while still holding the lock -- closing the window where a second scan could run before the first session's file exists on disk. The lock only spans this rare, brief start-up step, never a per-event write.



49
50
51
52
53
54
55
56
57
# File 'lib/bulldogger/record/writer.rb', line 49

def reserve_path(run_dir)
  @reserve_mutex.synchronize do
    existing = Dir.children(run_dir).filter_map { |name| name[FILENAME_PATTERN, 1]&.to_i }
    next_n = (existing.max || 0) + 1
    path = File.join(run_dir, format("trace-%03d.jsonl", next_n))
    FileUtils.touch(path)
    path
  end
end

Instance Method Details

#closeObject



35
36
37
38
# File 'lib/bulldogger/record/writer.rb', line 35

def close
  @io.close
  @path
end

#write_event(event) ⇒ Object



31
32
33
# File 'lib/bulldogger/record/writer.rb', line 31

def write_event(event)
  write_line(event)
end