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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
coverage.out
*.test
*.out
*.exe

# IDE
.idea/
Expand Down
4 changes: 4 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ linters:
- noinlineerr

settings:
exhaustive:
# A default case that handles remaining types is semantically exhaustive.
default-signifies-exhaustive: true

gocyclo:
min-complexity: 30

Expand Down
122 changes: 122 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Changelog

## Unreleased

### New features

- `FORCE_COLOR=<non-empty>` environment variable forces ANSI colour output regardless of whether stdout is a real terminal. Useful on Windows where terminal emulators proxy stdout through a named pipe, causing `term.IsTerminal` to return false even in a colour-capable terminal.
- `NO_COLOR=<non-empty>` environment variable unconditionally disables ANSI colour output, following the https://no-color.org convention. Takes precedence over `FORCE_COLOR`.
- `TTYRenderable` interface — optional extension to `Renderable` for types that need the terminal state at render time. `Logger.Render` and `Logger.RenderRaw` detect this interface and pass the console writer's resolved TTY state so colour decisions are correct even when rendering through an intermediate buffer.

### Bug fixes

- Console writer now correctly emits colour when no theme is explicitly configured; previously, the default-theme path silently disabled colour.
- `StatusItem`, `Group`, and `ContinuationBlock` now implement `TTYRenderable` and expose a `RenderTTY(w, isTTY)` method. Previously, when rendered via `Logger.Render`, `IsTerminalWriter` on the intermediate buffer always returned false, producing plain (uncoloured) badge/item output even on real terminals.
- `template.useColours` is now gated on actual TTY state at writer construction, not just on whether the theme has colours. Previously, ANSI sequences were always emitted when the theme was non-mono, including when stdout was a pipe or file.
- `ConsoleWriter.SetTheme` now updates `template.useColours` to reflect the new theme and current TTY state; previously it left `useColours=false` from initial construction when the writer was built on a non-TTY.
- `ConsoleWriterRB` now uses TTY detection (`resolveColourForWriter`) to set its trust state, matching `ConsoleWriter`'s model. Previously, the template path always rendered Secure fields as plaintext regardless of whether the output was a terminal or a file/pipe.
- `StatusItem.writeStatusFields` now applies the same TTY-as-trust model as `ConsoleWriter`: Secure fields show plaintext on terminal output and are redacted in plain (non-TTY) renders. Previously, Secure fields were always redacted in Status badge output even on trusted terminals.
- `SetTheme(nil)` now documents and enforces "nil = reset to NightOwl" semantics; `Style()` and `cfg.ConsoleTheme` both reflect the reset. Previously, the nil behaviour was not regression-tested.

## v2.0.0 — 2026-05-15

Tag when ready: `git tag v2.0.0 feature/v2`

### Breaking

- Module path changed to `github.com/tensorfoundrylabs/velocity/v2` — update all imports accordingly
- `NewWithBuilder`, `NewWithOptions`, `NewWithConfig`, `NewDevelopment`, `NewForTesting` removed — use `New(opts ...Option)` with preset options
- `NopLogger()` retained for compatibility — equivalent to `New(WithNop())`
- `Builder` type removed — configure via options only
- `Config` struct unexported — no direct field access
- `Default*Config` family removed
- `Fields` struct, `NewFields`, `F`, `Milliseconds` removed — use typed field constructors directly
- `*Detailed` methods removed (`DebugDetailed`, `InfoDetailed`, etc.) — use `Logger.Detailed()` for a child logger with tree display
- `Logger.Raw` removed
- `Logger.Banner` renamed to `Logger.BannerLines` (avoids collision with `Banner` renderable type)
- `Logger.SetTemplate` / `Logger.WithTemplate` removed
- `Logger.Status() *StatusFormatter` removed — use `Logger.Style() *Theme`
- `StatusFormatter` type removed
- `AtomicLevel` exported type removed — level is now an internal `atomic.Int32`
- `velocity/pretty` package removed — all renderables moved to root package
- `velocity/slog` package removed — replaced by `velocity/slogbridge` (`package slogbridge`)
- `BoxResult`, `TableResult`, `TreeResult`, `BannerResult`, `KeyValueResult`, `SystemInfoResult` removed — types renamed to `Box`, `Table`, `Tree`, `Banner`, `KeyValue`, `SystemInfo`
- `BulletResult` removed — `Bullet` was only ever a `Logger` method, not a standalone type
- `NewFromLogger` constructor pattern removed from pretty — use `Logger.Box(...)`, `Logger.Table(...)`, etc. directly
- Theme `Cache()` and `EnsureCached()` removed — themes are immutable post-construction
- Colour options consolidated to `WithColour(bool)`
- `WithDisplayTimezone` now takes `*time.Location` directly; helper `MustLocation(name string)` added
- `Logger.AddWriter` now accepts `...WriterOption` for trust and capability configuration

### New features

- `New(opts ...Option)` and `TryNew(opts ...Option)` — single constructor entry point
- Preset options: `WithDevelopment()`, `WithProduction()`, `WithContainer()`, `WithTesting(t)`, `WithNop()`, `WithHighThroughput()`
- `Logger.WithComponent(name string) *Logger` — named child logger
- `Logger.WithRequest(id string) *Logger` — request-scoped child logger
- `Logger.Detailed() *Logger` — child logger with forced tree display
- `Logger.Style() *Theme` — theme accessor
- `Logger.Close()` — idempotent, flushes all owned writers; after-close calls are silent no-ops
- `ParseLevel(string) (Level, error)` — non-panicking sibling to `MustParseLevel`
- `NewTheme(name, ...ThemeOption) *Theme` — immutable theme builder
- `StyleSlot` enum with 16 semantic slots: `SlotGood`, `SlotBad`, `SlotWarn`, `SlotMuted`, `SlotStrong`, `SlotHeading`, `SlotEndpoint`, `SlotHyperlink`, `SlotContinuation`, `SlotCount`, `SlotSecure`, `SlotStatusOK`, `SlotStatusFail`, `SlotStatusWarn`, `SlotStatusInfo`, `SlotTableHeader`
- `Theme.Format(slot, s)`, `Theme.Wrap(slot)`, `Theme.Stylish(w)` — theme styling API
- `ThemeMono` — new colour-free built-in theme
- Writer capability interfaces: `ThemedWriter`, `LeveledWriter`, `FlushableWriter`, `TrustedWriter`
- `WriterTrusted()` writer option — marks a writer as trusted for receiving un-redacted secure fields
- `FilteredWriter` — wraps any writer with level filtering
- `Logger.Writer(name) Writer` — accessor for named writers
- `Logger.RemoveWriter(name) Writer` — returns removed writer for caller cleanup
- `RingBufferWriter` — in-process log capture with `Snapshot`, `Subscribe`, `Stats`
- `EntrySnapshot` — deep-copy value type; redacted unless writer is trusted
- `RingStats` — capacity, fill, drop counts
- `Logger.Notify(format, args...)`, `Logger.NotifyLines(lines...)`, `Logger.NotifyBox(*Box)` — ephemeral operator output that bypasses structured pipeline
- `WithNotifyOutput(io.Writer)` — override notify target (default `os.Stderr`)
- Secure field constructors: `Secure(k, v)`, `SecureURL(k, u)`, `Redacted(k)`, `Truncated(k, v, maxLen)`
- `<secure>...</secure>` tag scanning in message strings — redacted in JSON and non-TTY console output
- `WithSecureTags(bool)` option — explicit opt-out of tag scanning
- `scanSecure` per-instance atomic flag — recomputed on writer add/remove; zero cost when all writers are trusted
- `StatusItem` renderable and `Logger.Status(level, kind, msg, fields...)` log-call form
- Console path: renders an inline indented badge (no timestamp, no level label) via `Logger.Render`
- JSON path: emits a full structured record with `"status"` field for log queries
- `NewStatusItem` no longer takes `isTTY bool` — TTY is resolved at `Render(w)` time
- `StatusKind` enum: `StatusOK`, `StatusFail`, `StatusWarn`, `StatusInfo`, `StatusPending`, `StatusSkipped`
- `Group` renderable and `Logger.Group(level, msg, items...)` — count-headed indented block
- `NewGroup` no longer takes `isTTY bool` — TTY resolved at `Render(w)` time
- `GroupItem{Marker, Text}` — individual group entry
- `ContinuationBlock` renderable and `Logger.Continue(level, msg, lines...)` — `│`-glyph continuation lines
- `NewContinuationBlock` no longer takes `isTTY bool` — TTY resolved at `Render(w)` time
- `Hyperlink(uri, text, ...opts) string` — OSC 8 hyperlink with TTY detection and three fallback modes
- `HyperlinkFallbackNone`, `HyperlinkFallbackParens`, `HyperlinkFallbackBrackets` — fallback modes
- `HyperlinksSupported()` — cached TTY detection
- `WithHyperlinkFallback(mode)` — per-call fallback override
- `Pretty` facade moved to root; `NewPretty(w, theme)` and `NewPrettyFromLogger(logger)` constructors
- Logger convenience methods: `Logger.Box`, `Logger.Table`, `Logger.Tree`, `Logger.BannerLines`, `Logger.KeyValues`, `Logger.SystemInfo` — render directly through console writer mutex
- `velocity/live` package — stateful animated types (`Spinner`, `ProgressBar`, `MultiProgress`) extracted from old `velocity/pretty`; all types suppress control sequences (\r, ANSI erase) when writer is not a terminal
- `velocity/slogbridge` — slog bridge package renamed, with corrected benchmark (was writing to stdout in v1)
- 18 examples covering all major features (up from 11 in v1)

### Performance

- `Info, 5 fields`: 38 ns → 33 ns (-13%); zero allocs preserved
- `Info, 10 fields`: 39 ns → 35 ns (-10%); zero allocs preserved
- `Info, tree mode`: 36 ns → 33 ns (-8%); zero allocs preserved
- `WithComponent child`: 270 ns → 159 ns (-41%); 3 allocs preserved
- `SecureScan_NoMatch`: 67 ns → 35 ns (-48%); zero allocs preserved; `IndexByte` fast-exit before any field inspection
- `slog handler, 3 attrs`: benchmark corrected (v1 was writing to stdout); real v2 cost is ~99 ns / 3 allocs / 144 B
- `Info, no fields`: 26 ns → 28 ns (+8%); scanSecure flag check adds ~2 ns on the no-field path
- `ConsoleWriter, 5 fields`: 433 ns → 483 ns (+12%); immutable theme lookup and writer capability checks added
- `JSONWriter, 5 fields`: 594 ns → 642 ns (+8%); `<secure>` tag scan path added; zero allocs preserved
- `BufferPool_GetPut`: 25 ns → 17 ns (-32%); tiered pool restructure
- Allocation profile unchanged on all zero-alloc paths

### Internal

- Package `velocity/pretty` eliminated; import cycle resolved by moving all renderables to root
- Package `velocity/slog` renamed `velocity/slogbridge` (`package slogbridge`)
- Package `velocity/live` created for stateful animated types
- `AtomicLevel` is now an internal `atomic.Int32`; API surface uses `Level` type throughout
- Theme construction is eager — no `sync.Once`, no `Cache()` call needed by callers
- `scanSecure atomic.Bool` recomputed on writer topology changes, not per log call
- All built-in themes ported to `NewTheme` immutable form
- `slogbridge` benchmark fixed to use `WithNop()` instead of writing to stdout
Loading
Loading