Skip to content

refactor: improve performance and usability of error handling#12

Merged
rjfonseca merged 1 commit into
mainfrom
feat/fmt-and-slog-support
May 13, 2026
Merged

refactor: improve performance and usability of error handling#12
rjfonseca merged 1 commit into
mainfrom
feat/fmt-and-slog-support

Conversation

@rjfonseca
Copy link
Copy Markdown
Member

  • Implement KV batching using slices in Error struct to reduce depth of error chains
  • Remove runtime reflection from 'With' for lazy validation (perf gain on creation path)
  • Optimize 'Value' and 'Format' lookups (30-40% faster read/format performance)
  • Implement slog.LogValuer for native structured logging integration
  • Implement fmt.Formatter for rich error output with %+v
  • Add permanent bench_test.go for performance tracking
  • Add AI Agent Skill for package usage guidance

Benchmark results:

  • BenchmarkFormatFull: 790 ns/op -> 464 ns/op (-41%)
  • BenchmarkValue: 44 ns/op -> 31 ns/op (-30%)

@rjfonseca rjfonseca requested a review from victormn March 3, 2026 11:32
@rjfonseca rjfonseca requested a review from xico42 as a code owner March 3, 2026 11:32
Copilot AI review requested due to automatic review settings March 3, 2026 11:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors github.com/arquivei/errors to improve performance and usability by batching key/value context on each wrapper error, optimizing lookups/formatting, and adding native interoperability with Go’s fmt and log/slog.

Changes:

  • Refactor With/Error to store multiple KeyValuers per wrapper (shallower chains) and update lookup helpers accordingly.
  • Add fmt.Formatter (%+v) and slog.LogValuer support for better stdlib integration.
  • Add permanent benchmarks and update documentation/examples to reflect new behaviors.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
with.go Changes With to batch KVs into a slice and adjusts automatic Op behavior.
value.go Updates value/values/map extraction to iterate the new per-error keyvals slice.
op.go Optimizes Op-stack building by scanning keyvals directly.
kv.go Extends stringify to better handle nil, bool, and error.
formatter.go Tweaks builder initialization/growth for formatter performance.
error.go Changes Error() semantics and adds fmt.Formatter + slog.LogValuer implementations.
with_test.go Updates panic expectations for non-comparable keys.
bench_test.go Adds benchmarks for With/Value/Format and standard %+v formatting.
example/main.go Demonstrates %v/%+v and slog integration.
README.md Adds interoperability docs and updates surrounding sections.
.agents/skills/arquivei-errors/SKILL.md Adds usage guidance for the package (AI agent skill).
Comments suppressed due to low confidence (1)

README.md:195

  • The docs state that a Formatter "changes the behavior of Error() string", but Error.Error() now returns only the wrapped/root message regardless of attached Formatter. Please update this section (and example) to match the new behavior so users don’t rely on Error() being affected by errors.With(err, errors.KVFormatter/FullFormater/etc).
### Formatter

This is a special type that changes the behavior of `Error() string`  function.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread error.go Outdated
Comment thread error.go Outdated
Comment thread README.md
Comment thread value.go Outdated
Comment thread error.go
Comment thread with_test.go Outdated
Comment thread README.md Outdated
Comment thread with.go Outdated
Comment thread value.go Outdated
@rjfonseca rjfonseca force-pushed the feat/fmt-and-slog-support branch 2 times, most recently from 10b956a to 946644b Compare March 3, 2026 16:43
Comment thread skills/arquivei-errors/SKILL.md
@rjfonseca rjfonseca force-pushed the feat/fmt-and-slog-support branch 4 times, most recently from be261ab to d53ce88 Compare May 13, 2026 18:45
@rjfonseca rjfonseca requested review from Copilot and xico42 May 13, 2026 18:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (3)

kv.go:37

  • Changing KV to a generic KV[K comparable] is a public API breaking change: callers that currently hold keys as any/interface{} (or other non-comparable-constrained interfaces) will no longer compile even if the dynamic value is comparable. If you want compile-time safety without breaking existing users, consider keeping the old KV(key any, value any) (with runtime validation) and adding a new generic helper (or an alternate constructor) for compile-time enforcement.
// KV is a constructor for KeyValuer types.
// It ensures at compile-time that the provided key is of a comparable type.
func KV[K comparable](key K, value any) KeyValuer {
	return KeyValue{
		key:   key,
		value: value,
	}
}

go.mod:6

  • go is set to 1.24 but toolchain is set to go1.26.3. If the codebase truly requires 1.26 features, the go directive should be updated accordingly; otherwise, pinning a newer toolchain than the module version can unnecessarily force toolchain downloads and complicate CI/reproducibility.
go 1.24

toolchain go1.26.3

README.md:195

  • The new “Standard Formatting” section says %v/.Error() print only the root error message, but later the README still states that a Formatter “changes the behavior of Error() string”. After this PR, Error.Error() always returns the wrapped error’s message and ignores any formatter in the chain, so the formatter docs/examples should be updated to avoid misleading users (it affects errors.Format(err), not err.Error()).
### Standard Formatting

The `Error` struct also implements the `fmt.Formatter` interface.
Using `%+v` with `fmt.Printf` will automatically yield the rich format output (the same as `errors.Format(err)`), allowing you to skip explicitly calling `Format` in standard log prints.

### Formatter

This is a special type that changes the behavior of `Error() string`  function.

Comment thread with.go
Comment thread op.go
Comment thread value.go
Comment thread README.md Outdated
- Enforce comparable keys at compile time using Generics on KV constructor
- Optimize 'Value' and 'Format' lookups avoiding intermediate slice allocations
- Implement slog.LogValuer for native structured logging integration
- Implement fmt.Formatter for rich error output with %+v
- Add permanent bench_test.go for performance tracking
- Add AI Agent Skill for package usage guidance

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@rjfonseca rjfonseca force-pushed the feat/fmt-and-slog-support branch from 26f7c29 to ee774c3 Compare May 13, 2026 19:09
@rjfonseca rjfonseca merged commit 76e22b1 into main May 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants