Documentation
¶
Overview ¶
Package logwriter provides atomic NDJSON event writing with optional size-based rotation for workspace logs and no rotation for per-slot logs.
Atomicity: each Append opens the file with O_APPEND|O_CREATE|O_WRONLY and writes a single newline-terminated line. POSIX guarantees that writes no larger than PIPE_BUF (512 bytes minimum; 4096+ on Linux and macOS) are atomic on append-only file descriptors, so concurrent slot processes cannot interleave lines for the small payloads we emit (~150–300 bytes).
Rotation (workspace log only): on every Append, the file is stat-ed; if its size exceeds maxSize the numbered series is shifted (.log.1→.log.2, etc.), the current .log is renamed to .log.1, and a fresh .log is opened. The oldest numbered file is removed when the count exceeds maxFiles.
Single-writer assumed for v1 (one process appending per file at a time). Concurrent-process safety relies on O_APPEND atomicity but NOT on rotation being race-free — do not call Append concurrently on the same Writer.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendOnce ¶
AppendOnce writes one event line to path without rotation. Use this for per-slot logs and other call sites that don't carry rotation state across calls — it skips the Writer allocation entirely. The parent directory is created if absent.
Atomicity: opens with O_APPEND|O_CREATE|O_WRONLY and writes a single newline-terminated line. POSIX guarantees writes ≤PIPE_BUF are atomic.
func SlotLogPath ¶
SlotLogPath returns the per-slot log path under <slotDir>/log. Per-slot logs are bounded by slot lifetime and never rotate, so callers should use AppendOnce(SlotLogPath(slotDir, slot), event) — no Writer needed.
Types ¶
type Event ¶
type Event struct {
Timestamp time.Time `json:"-"`
Slot string `json:"-"` // optional; omitted when empty
Event EventType `json:"-"`
Fields map[string]interface{} `json:"-"`
}
Event is one NDJSON row. MarshalJSON merges Fields into the top-level object so the on-disk row is flat: {"ts":"...","event":"...","slot":"...",...fields}. json:"-" tags keep the zero-value encoding path from double-emitting keys.
func (Event) MarshalJSON ¶
MarshalJSON emits a single flat JSON object. Required keys are always present; "slot" is omitted when empty; entries from Fields are merged at the top level. If a Fields key collides with a reserved key ("ts", "event", "slot") it is silently dropped — callers must not reuse reserved names.
type EventType ¶
type EventType string
EventType is one entry in the closed catalog of slot/workspace event kinds. Each constant matches the string written to the on-disk NDJSON "event" field so operator tooling can grep without understanding Go constants.
const ( // EventJoin is emitted when a slot successfully acquires a session. EventJoin EventType = "join" // EventCommit is emitted when a slot's commit completes without error. EventCommit EventType = "commit" // EventCommitError is emitted when a slot's commit fails. EventCommitError EventType = "commit_error" // EventRenew is emitted when a slot renews its lease. EventRenew EventType = "renew" // EventClose is emitted when a slot closes and releases its session. EventClose EventType = "close" // EventDispatched is emitted when the workspace dispatches a new plan. EventDispatched EventType = "dispatched" // EventError is emitted for any unexpected error worth recording. EventError EventType = "error" )
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer writes NDJSON event lines to a single file, optionally rotating on size. Zero value is not valid; use Open or OpenSlot.
func Open ¶
Open returns a Writer for the workspace log at path. Defaults: 10 MiB maxSize, 5 backup files. Overridable via BONES_LOG_MAX_SIZE (bytes) and BONES_LOG_MAX_FILES.