Skip to content

Releases: tensorfoundrylabs/velocity

Velocity v2.3.0

Choose a tag to compare

@thushan thushan released this 20 Sep 11:19
v2.3.0
503c0c0

Velocity v2.3.0 adds opt-in non-blocking structured output and fixes error rendering in Any fields.

Added

  • WithAsyncOutput(AsyncConfig{Queue, OnFull}) makes the primary structured (JSON) output non-blocking. Callers format each record exactly as before, then enqueue the finished bytes onto a bounded queue drained by a single goroutine that performs the write, so no syscall (and no mutex held across one) runs on the logging goroutine. OnFull selects AsyncBlock (lossless back-pressure over Queue records of headroom, then the caller back-pressures to the sink's write rate; the default) or AsyncDrop (never block; losses counted and reported via Logger.StructuredDroppedCount and JSONWriter.DroppedCount; the choice for availability-critical request paths). Default queue depth is DefaultAsyncQueue (8192), about 140ms of burst headroom at 60k lines/s; formatting buffers live in sync.Pool, so the queue retains nothing itself and the collector reclaims idle buffers (the first Queue records warm the pool once, 16 MiB at the default depth). Fatal delivery stays reliable and ordered behind a barrier before the FatalHandler runs; Flush and Close drain everything accepted, with no timeout, and worst-case Close performs Queue sink writes, so a deadline-bounded caller must bound Close itself. Console output is unaffected. Without the option, behaviour is unchanged and the synchronous path gains no allocations.
  • NewAsyncJSONWriter(out, AsyncConfig) constructs the async JSON writer directly.
  • WithWriterQueueDepth(n) (WriterOption) configures the per-writer channel depth MultiWriter allocates in AddWriter, previously hardcoded at 256 (still the default; non-positive values fall back to it).

Fixed

  • An Any field holding an error now renders its Error() message as a JSON string, and a fmt.Stringer whose marshaled form is an empty object renders String(). Since v2.2.0 Any renders through json.Marshal, which only sees exported fields, so errors.New, fmt.Errorf, every runtime.Error and any opaque struct logged as {} and a recovered panic lost its message. This is a behaviour change from v2.2.0's {} output: those values now appear as their text. Precedence: a json.Marshaler's explicit form wins when MarshalJSON succeeds (a structured error carrying MarshalJSON keeps its shape); a failing MarshalJSON falls through, then Error() for errors, then String() for stringers that marshal to {}. Typed nils render null instead of panicking on a nil receiver.

Performance

Measured on the Ryzen 9 5950X, interleaved runs. Per-call cost through a full logger against a free sink: 520 ns sync, 681 ns async, both 0 allocs/op. Against a sink charging a serialised 2 µs per write at 32 goroutines: 2733 ns/op sync, 2244 ns/op AsyncBlock, 240 ns/op AsyncDrop (90% dropped under that flood, every loss counted). The synchronous path is unchanged: identical allocation counts, timing within code-layout jitter (JSONWriter_Parallel main vs this tree p>0.6).

Velocity v2.2.1

Choose a tag to compare

@thushan thushan released this 19 Sep 09:17
v2.2.1
2ebb963

Fixes and leaner logging from the post-v2.2.0 review round. No public API changes.

Fixes

  • Malformed UTF-8 in JSON output is replaced with U+FFFD escapes instead of producing invalid JSON; valid Unicode passes through untouched.
  • Millisecond timings in inline indicators no longer overflow into nanoseconds.
  • The count, timing and state-transition indicator options now properly remove promoted fields from the pretty tree.
  • Pooled entries clear stale field references through the whole slice on reset, so reused entries can't observe old pointers.

Leaner logging

  • Floats format straight into concrete buffers, no temporaries.
  • JSON buffers up to 32 KiB are reused; bigger ones aren't hoarded by the pool, and oversized ring batches are released instead of pinned at peak size.
  • Snapshot copies are skipped for subscribers whose queue is already full.
  • slogbridge prepends fields without a temporary slice, and Detailed children share the parent's immutable base fields.
  • Status caller line numbers go through the stack buffer.

Tooling

  • Gate tools are pinned and make ready is read-only, with formatter failures reported. Dev tooling needs a newer toolchain than the library's Go 1.24 minimum; the library itself still supports 1.24.

Velocity v2.2.0

Choose a tag to compare

@github-actions github-actions released this 16 Sep 11:46
v2.2.0
01174b6

Logging hardening: reliable shutdown, secure redaction, stable live output, and honest benchmarks.

Four independently reviewed fix-and-verification rounds went into this release. Every fix ships with a permanent regression test; the full finding-to-test mapping and measurement artifacts live in docs/specs/ and docs/benchmarks/ in the development tree.

Behaviour changes

  • Shared family lifetime. Once any Close completes, the whole parent/child family is closed for good: later log calls are dropped, AddWriter can no longer revive output, and concurrent Close calls all wait for the same drain and return the same recorded result. Close drains calls that were already admitted - console and JSON writes register as in-flight for the whole formatting cycle, and the render helpers (Render, RenderRaw, Newline, BannerLines, KeyValues, Bullet) register before running - so an admitted call completes rather than writing after Close returned. Admitted family output (including Notify) finishes before the final destination flush, so notifications shared with console logging on one buffered sink are always emitted.
  • Reliable fatal delivery. Logger.Fatal is exempt from the sampler in every dispatch path and waits for preceding accepted entries, its own write, and a flush before invoking FatalHandler/exiting. Delivery is acknowledged per queue item (a FIFO barrier sentinel closed by the worker that dequeues it), so the wait cannot be satisfied early by racing aggregate counters. A custom handler that returns leaves the logger reusable. LogEntry and slog records at LevelFatal are logged but never exit the process.
  • Content-driven <secure> tag handling. The maybe-secure flag derives from message content whenever scanning is enabled, independent of the writer mix, so adding a writer after a scan can no longer leak plaintext. On all-trusted topologies markers are stripped (plaintext shown); untrusted writers still see redaction. Group item text and continuation lines follow the same policy as headers on console and JSON.
  • Colour permission fixed at construction. WithColour(false) survives every theme swap; a mono-to-coloured swap restores colour only where permission allows. FORCE_COLOR can style non-terminals but never grants trust or cursor control. Logger.Status now respects the resolved colour permission on terminals, with styling and trust propagated separately - a trusted terminal with styling disabled still shows Secure field plaintext, without ANSI.
  • Honest close errors. MultiWriter.Close (and Logger.Close through it) returns worker close errors joined with errors.Join.
  • Deprecated ConsoleWriterRB: the ring-full direct-write fallback is removed - a full queue drops the record, counts it in DroppedCount, and Write returns nil; a second Close waits for the same drain and returns nil. Scheduled for removal in v3; use ConsoleWriter.
  • Stable live displays. Widgets finalise exactly once (concurrent Stop/Complete all wait for the one finalisation, no output after), cursor-control capability depends on the real destination rather than FORCE_COLOR, and multi-row displays no longer walk down the terminal on each repaint: repeated repaints, grow/shrink, widget removal and interleaved log lines hold a stable vertical position.
  • Terminal cell widths. Table, box, banner, component-column and truncation widths are measured in terminal cells (uniseg grapheme widths) with an allocation-free printable ASCII fast path. Absent table cells are padded to the declared geometry; negative Bullet nesting is clamped.

New APIs

  • live.NewOutput(io.Writer) *live.Output - opt-in shared terminal coordinator. Pass the same *Output to WithConsoleOutput and the widget constructors so log records and live displays serialise on one destination.
  • StyledRenderable - optional extension to Renderable for types that need resolved styling and trust propagated separately at render time (RenderStyled(w, styled, trusted)). Logger.Render/RenderRaw dispatch to it first; StatusItem implements it. Legacy Renderable and TTYRenderable implementations are unaffected.
  • velocity.Uint64(key string, val uint64) Field - lossless unsigned integer field on every output path, stored as bits without a float64 round trip.

Internal

  • ringbuffer.go rewritten as a mutex-guarded bounded byte queue with owned byte storage and a single drainer goroutine; the speculative CAS/skip reclamation protocol is gone.
  • The unused per-Logger buffer pool was removed; WithBufferSize and WithFieldPoolSize remain deprecated compatibility options.
  • PutFieldSlice clears the pooled slice through its capacity, so a later, smaller use cannot observe stale field pointers.
  • New direct dependency: github.com/rivo/uniseg v0.4.7 (terminal cell widths). golang.org/x/term remains.

Performance

Benchmarks now measure real serialisation (the previous fixtures routed enabled paths to io.Discard, which Velocity maps to a no-output fast path - the old numbers measured almost nothing). Corrected, interleaved measurements with a stable control benchmark are published in the README alongside delivery/drop ratios for the async figures. Disabled-level logging remains 0 B/op, 0 allocs/op, asserted by test.

Velocity v2.1.0

Choose a tag to compare

@github-actions github-actions released this 11 Jun 12:44
cab9251

Velocity v2.1.0

Fast, zero-allocation structured logging for Go with rich terminal output.

Install

go get github.com/tensorfoundrylabs/velocity@v2.1.0

Changelog

Other

  • dc693a5: add WithLevels to set console and structured thresholds together (@thushan)
  • 6599a8c: clamp effective log level to only reflect outputs that actually exist (@thushan)
  • b827ddc: copy-on-write in ConsoleWriter.SetTheme to eliminate race with WriteSecure template snapshot (@thushan)
  • 4621823: deprecate ConsoleWriterRB, fix direct-write fallback race, and honour NO_COLOR/TTY detection (@thushan)
  • d69e677: eliminate per-call heap allocation in PutFieldSlice by recycling the wrapper pointer (@thushan)
  • e119a84: expose a drop counter on MultiWriter to match RingBuffer (@thushan)
  • 6f0153d: fix caller off-by-one for Status/Group/Continue (3-frame paths were skipping 4) (@thushan)
  • b0c8db1: fix doc drift (AtomicLevel) and make banner box corners consistently single-line (@thushan)
  • c973e95: fix field corruption when LogEntry prepends base fields into a shared backing array (@thushan)
  • bbd93e9: fix visibleLen to skip OSC 8 hyperlink escape sequences in column-width maths (@thushan)
  • 934c610: guard logStatusStructuredWithFields mw nil-check under RLock to prevent race (@thushan)
  • 0211670: halve syscalls per JSON entry by appending the newline to the buffer before writing (@thushan)
  • 9542fd7: make isTerminal use term.IsTerminal for any *os.File, not just the three std streams (@thushan)
  • fface90: mark the release v2.1.0 and note CallerEnabled as a new feature (@thushan)
  • cab9251: merge v2.1 performance, concurrency and correctness fixes (@thushan)
  • a3dc63c: replace UnsafeString of stack-local buffer in FieldValueToString with FormatInt (@thushan)
  • 8c6b9f4: resolve slog record.PC into caller fields when velocity caller capture is enabled (@thushan)
  • 790311b: return a singleton nop logger from FromContext on miss instead of allocating each time (@thushan)
  • 2031e00: run gofumpt across themes, examples and tests (@thushan)
  • 7cbb123: stop ring-buffer flusher busy-polling when idle by parking on a write signal channel (@thushan)
  • d4ea3a3: switch MultiWriter.Write to RLock so concurrent writes don't serialise on a single mutex (@thushan)
  • 2691b1d: tidy struct field alignment and gofumpt formatting (@thushan)
  • 440e042: update changelog with v2.0.3 bug-fix entries (@thushan)

Docs: pkg.go.dev/github.com/tensorfoundrylabs/velocity

Velocity v2.0.2

Choose a tag to compare

@github-actions github-actions released this 30 May 08:13
28cf989

Velocity v2.0.2

Fast, zero-allocation structured logging for Go with rich terminal output.

Install

go get github.com/tensorfoundrylabs/velocity@v2.0.2

Changelog

Other

  • 28cf989: pin display timezone in indicator tests so golden output is host-TZ independent (@thushan)

Docs: pkg.go.dev/github.com/tensorfoundrylabs/velocity

Velocity v2.0.0

Choose a tag to compare

@github-actions github-actions released this 16 May 02:33
64a54ca

Velocity v2.0.0

Fast, zero-allocation structured logging for Go with rich terminal output.

Install

go get github.com/tensorfoundrylabs/velocity@v2.0.0

Changelog

Other

  • 049605f: ConsoleWriterRB: use isTTY trust model so Secure fields are redacted on non-TTY output (@thushan)
  • f386cc4: SetTheme(nil) regression test: Theme/Style/cfg all agree on NightOwl after reset (@thushan)
  • afba7ac: Status: gate on sampler, include baseFields, redact secure tags on console path (@thushan)
  • 9a4e6fa: StatusItem: apply trust-aware rendering to Secure fields so TTY shows plaintext (@thushan)
  • 5864eb2: add ContinuationBlock renderable for inline banner output (@thushan)
  • dec780e: add Group renderable for count-headed indented blocks (@thushan)
  • 6575387: add Hyperlink helper with OSC 8 and TTY detection (@thushan)
  • d305973: add Logger pretty conveniences for renderables in root (@thushan)
  • 074821b: add Notify channel for ephemeral operator output (@thushan)
  • 529e336: add RingBufferWriter built-in for in-process log capture (@thushan)
  • 7e41473: add StatusItem renderable and Logger.Status method (@thushan)
  • fbbbe5f: add field-level redaction and tag with auto-skip (@thushan)
  • 00d25ac: add v1.1.3 perf baseline and CI alloc-regression gate (@thushan)
  • 3ef13ae: add writer capability interfaces and per-writer trust opt-in (@thushan)
  • e11288f: bump module path to /v2 for semver compliance (@thushan)
  • 59da601: clarify RemoveWriter doc: worker closes the writer, do not double-close (@thushan)
  • d21ce3c: consolidate Logger surface; Detailed/Component/Request as child loggers (@thushan)
  • 42cd68d: docs (@thushan)
  • a1fd4f7: examples polish: pretty-output mutex, stale comments, badge token, makefile default (@thushan)
  • ce66b68: extract stateful types to velocity/live, kill pretty package (@thushan)
  • ac1b123: fix Logger.Style fallback so colour follows the active theme (@thushan)
  • 67b99e4: fix NO_COLOR and piped-mode ANSI leaks in renderables and Pretty (@thushan)
  • d5b6bd1: fix WithProduction routing to stderr — was nil, so no output was produced (@thushan)
  • b7ad101: fix colour pipeline end-to-end: FORCE_COLOR/NO_COLOR, TTY-gated templates, TTYRenderable (@thushan)
  • 75d8be6: fix console writer to emit colour when no theme is explicitly configured (@thushan)
  • 52b7806: fix examples: use log.Style() and gate hyperlinks on TTY (@thushan)
  • 6204677: fix race on afterSequenceSpinHook test hook via atomic pointer (@thushan)
  • 0dba400: fix scanSecure propagation to child loggers created before AddWriter (@thushan)
  • 5000008: gate hyperlinks on real TTY in examples; fix ring-buffer subscriber race (@thushan)
  • 194ea5a: gofumpt: collapse consecutive bool params in writeStatusFields (@thushan)
  • d858b8e: kill Builder; single New() with option presets (@thushan)
  • 81eb5e3: live: honour NO_COLOR and FORCE_COLOR env vars in progress and spinner types (@thushan)
  • 372953b: live: skip control sequences when writer is not a terminal (@thushan)
  • 6392d69: make status badges compact and uniform; OK->OKAY, PENDING->WAIT (@thushan)
  • 733833d: merge Pretty facade into root, drop method/constructor asymmetry (@thushan)
  • 3c2e892: move renderables to root, drop Result suffix (@thushan)
  • 6fa488c: polish examples and docs for v2; add hyperlinks example (@thushan)
  • fbb7ead: pre-tag cleanup: corrected comparative benchmarks, refresh stale docs (@thushan)
  • f6d6dd3: rebuild theme as immutable construct; add semantic style slots (@thushan)
  • 403d22e: redesign Logger.Status to render inline; drop isTTY from renderable constructors (@thushan)
  • aaf4068: rename slog bridge package to slogbridge (@thushan)
  • cddd668: retain NopLogger; fix changelog NopLogger and Bullet entries (@thushan)
  • 1ecf8d1: rewrite CLAUDE.md for v2.0: tighter, dropped test-file table, removed legacy notes (@thushan)
  • fd5a65d: run secure tag scan in LogEntry so slogbridge messages get redacted (@thushan)
  • 218e1ed: share writer topology between parent and child loggers via writerSet (@thushan)
  • de26800: split perf-gate out of make ready into its own target (@thushan)
  • 1f4583e: tolerate Sync errors on Close so redirected stdout doesn't panic (@thushan)
  • 9ed9121: update changelog with v2 review fixes: ConsoleWriterRB trust, StatusItem Secure fields (@thushan)
  • 9db3154: v2.0.0 bench baseline, changelog, and final docs (@thushan)

Docs: pkg.go.dev/github.com/tensorfoundrylabs/velocity

Velocity v1.1.3

Choose a tag to compare

@github-actions github-actions released this 08 May 12:26
376209b

Velocity v1.1.3

Fast, zero-allocation structured logging for Go with rich terminal output.

Install

go get github.com/tensorfoundrylabs/velocity@v1.1.3

Changelog

Other

  • 724d436: auto-cache themes at entry points so user-defined themes render colours (@thushan)
  • 0e4dfd6: examples: add indented table case demonstrating log.Render (@thushan)
  • d8bce56: recompute template cache after applying custom TimeFormat (@thushan)
  • 4d92edc: recompute template cache after console writer mutations to keep widths in sync (@thushan)
  • 376209b: switch theme caching to sync.Once for in-place, concurrent-safe population (@thushan)

Docs: pkg.go.dev/github.com/tensorfoundrylabs/velocity

Velocity v1.1.2

Choose a tag to compare

@github-actions github-actions released this 08 May 11:20
dbd9971

Velocity v1.1.2

Fast, zero-allocation structured logging for Go with rich terminal output.

Install

go get github.com/tensorfoundrylabs/velocity@v1.1.2

Changelog

Other

  • dbd9971: examples: indent deployment tree under log line in terminal-velocity (@thushan)
  • bc21594: examples: revert section headers to fmt.Println, fix table alignment (@thushan)
  • da67324: revert NewFromLogger to flush-left output; use log.Render explicitly for indented blocks (@thushan)
  • 7b80483: route NewFromLogger writes through Render so output indents under message column (@thushan)
  • f0c6147: use accurate message column for Logger.Render indent (@thushan)

Docs: pkg.go.dev/github.com/tensorfoundrylabs/velocity

Velocity v1.1.1

Choose a tag to compare

@github-actions github-actions released this 08 May 10:27
746c035

Velocity v1.1.1

Fast, zero-allocation structured logging for Go with rich terminal output.

Install

go get github.com/tensorfoundrylabs/velocity@v1.1.1

Changelog

Other

  • 746c035: indent first line in Logger.Render so table top borders align (@thushan)

Docs: pkg.go.dev/github.com/tensorfoundrylabs/velocity

Velocity v1.1.0

Choose a tag to compare

@github-actions github-actions released this 08 May 10:03
17403b2

Velocity v1.1.0

Fast, zero-allocation structured logging for Go with rich terminal output.

Install

go get github.com/tensorfoundrylabs/velocity@v1.1.0

Changelog

Other

  • 6494500: LogEntry: avoid make() for base field prepend, reuse entry slice (@thushan)
  • bbc55a6: add Logger.Render tests for JSON writer ignore and no-console-writer no-op paths (@thushan)
  • 7783ae1: add Logger.Render, RenderRaw, Newline for terminal-aligned rich output (@thushan)
  • 6082e53: add Logger.SetTheme to update theme on active writers (@thushan)
  • 3a8a76e: add Renderable interface and extract render logic into result types in pretty (@thushan)
  • 077858b: add Renderable interface compliance and parity tests for pretty result types (@thushan)
  • 4266ff7: add benchmarks for Render API and pretty.NewFromLogger paths (@thushan)
  • 3986197: add deterministic regression test for ring buffer write claim race (@thushan)
  • 2f1f89c: add missing doc comment on pretty.New (@thushan)
  • ec32b58: add pretty.NewFromLogger and Logger.Theme, route pretty output through logger mutex (@thushan)
  • 668e8a9: add tree-mode benchmarks to validate zero-alloc cachedIndentStr path (@thushan)
  • 14754c3: align Template struct after cachedIndentStr addition (@thushan)
  • 6f193cc: apply gofumpt formatting (@thushan)
  • 739894c: cache indent string on template, drop strings.Repeat per tree-mode log call (@thushan)
  • 342d3d8: cache prefix width on Template at construction, skip repeated calculatePrefixWidth in badge tree mode (@thushan)
  • 2805ad9: cache table header and info colour ANSI strings on Theme (@thushan)
  • aaa7c19: console writer: use fmt.Fprintf for FieldTypeAny to avoid intermediate string alloc (@thushan)
  • aa48b88: drop eager bytes.Buffer alloc from entryPool.New (@thushan)
  • 521bda2: examples: drop fmt.Fprintln spacers, use log.Newline and Render API (@thushan)
  • 9dfa26b: examples: indent tables under log lines via Render (@thushan)
  • 7d38e18: extend SetTheme tests: Theme() getter, multi-writer propagation, With() clone inheritance (@thushan)
  • 30a15a4: fix calculatePrefixWidth to use reference time, not entry time (@thushan)
  • 31018f4: fix race in ring buffer write section and settheme test (@thushan)
  • e82ea58: json writer: inline hex escape for control chars, drop fmt.Fprintf alloc (@thushan)
  • 91b3c15: pretty: pool bytes.Buffer via root GetBuffer/PutBuffer instead of per-render alloc (@thushan)
  • 5ea3185: pretty: use cached ANSI strings from Theme instead of calling ANSI() per render (@thushan)
  • 552e662: replace strconv.Itoa with AppendInt into stack buf for caller line in template (@thushan)
  • af15df9: replace strconv.Itoa with formatInt+UnsafeString in FieldValueToString (@thushan)
  • 593265d: ring buffer writer: default nil timezone to time.Local, drop runtime nil-check in formatEntry (@thushan)
  • ca21c24: tighten docs and nil-safety on v1.1 api (@thushan)
  • 17403b2: tighten readme and refresh internal benchmarks for v1.1 (@thushan)
  • dfec02c: tighten ring buffer high-throughput test with sequenced payloads (@thushan)

Docs: pkg.go.dev/github.com/tensorfoundrylabs/velocity