惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
Apple Machine Learning Research
Apple Machine Learning Research
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
M
MIT News - Artificial intelligence
腾讯CDC
B
Blog RSS Feed
H
Help Net Security
J
Java Code Geeks
有赞技术团队
有赞技术团队
Y
Y Combinator Blog
博客园_首页
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
博客园 - Franky
B
Blog
MongoDB | Blog
MongoDB | Blog
博客园 - 叶小钗
Martin Fowler
Martin Fowler

Dizzy zone

Pangolin Private Resources With Domain Https About Redis is fast - I'll cache in Postgres n8n and large files Malicious Node install script on Google search BLAKE2b performance on Apple Silicon State of my Homelab 2025 My homelabs power consumption On Umami ML for related posts on Hugo Probabilistic Early Expiration in Go SQLC & dynamic queries Enums in Go Streaming Netdata metrics from TrueNAS SCALE SQL string constant gotcha Moving from Jenkins to Drone My new server: MSI Cubi 3 Silent My thoughts on Ansible® Profiling gin with pprof How I host this blog, CI and tooling Refactoring Go switch statements OAuth with Gin and Goth I made my own commenting server. Here's why. Why I hate OpenApi(swagger) IDE for GO Jenkins on raspberry pi 3 How I started my professional career Kestrel vs Gin vs Iris vs Express vs Fasthttp on EC2 nano Go's defer statement Self-hosted disqus alternative for 5$ a month
Wrapping Go errors with caller info
Vik · 2025-07-11 · via Dizzy zone

I find Go’s error handling refreshingly simple & clear. Nowadays, all I do is wrap my errors using fmt.Errorf with some additional context. The pattern I tend to use most of the time just includes a function/method name, like so:

func someFunction() error {
	err := someStruct{}.someMethod()
	return fmt.Errorf("someFunction: %w", err)
}

type someStruct struct {
}

func (ss someStruct) someMethod() error {
	return fmt.Errorf("someMethod: %w", errors.New("boom"))
}

If I now call someFunction, the error - when logged or printed - will look like this: someFunction: someMethod: boom. This gives just enough context to figure out what happened, and where.

I thought to myself - this can be wrapped in a helper function, to automatically take the caller name and do this wrapping for me.

Here’s an implementation:

func WrapWithCaller(err error) error {
	pc, _, line, ok := runtime.Caller(1)
	if !ok {
		return fmt.Errorf("%v: %w", "unknown", err)
	}
	fn := runtime.FuncForPC(pc).Name()
	pkgFunc := path.Base(fn)
	return fmt.Errorf("%v:%d: %w", pkgFunc, line, err)
}

We can now use it like so:

func someFunction() error {
	err := someStruct{}.someMethod()
	return WrapWithCaller(err)
}

type someStruct struct {
}

func (ss someStruct) someMethod() error {
	return WrapWithCaller(errors.New("boom"))
}

And it will return the following: main.someFunction:45: main.someStruct.someMethod:52: boom. Keep in mind that this will have performance overhead:

func Benchmark_WrapWithCaller(b *testing.B) {
	err := errors.New("boom")
	for i := 0; i < b.N; i++ {
		_ = WrapWithCaller(err)
	}
}
// Result:
// Benchmark_WrapWithCaller-10    	 2801312	       427.0 ns/op	     344 B/op	       5 allocs/op

func Benchmark_FmtErrorf(b *testing.B) {
	err := errors.New("boom")
	for i := 0; i < b.N; i++ {
		_ = fmt.Errorf("FmtErrorf: %w", err)
	}
}

// Result:
// Benchmark_FmtErrorf-10    	13475013	        87.19 ns/op	      48 B/op	       2 allocs/op

So it’s 4-5 times slower than a simple wrap using fmt.Errorf.

One benefit of using WrapWithCaller is that refactoring is easier - you change the function/method name and don’t need to bother yourself with changing the string in the fmt.Errorf. The performance hit is likely not an issue for most programs, unless you’re wrapping tons of errors in hot loops or something like that.

I’m a bit torn if I want to add this helper to my codebases and use it everywhere - seems like an extra dependency with little benefit, but I’ll have to give it a spin before I decide if this is something I’m ready to accept. Time will tell. Thanks for reading!