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

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Azure Blog
Microsoft Azure Blog
Cloudbric
Cloudbric
I
InfoQ
V
V2EX
博客园_首页
The Register - Security
The Register - Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Secure Thoughts
Vercel News
Vercel News
Forbes - Security
Forbes - Security
云风的 BLOG
云风的 BLOG
PCI Perspectives
PCI Perspectives
L
LINUX DO - 最新话题
D
DataBreaches.Net
H
Hacker News: Front Page
Application and Cybersecurity Blog
Application and Cybersecurity Blog
B
Blog RSS Feed
A
About on SuperTechFans
N
News and Events Feed by Topic
Apple Machine Learning Research
Apple Machine Learning Research
Help Net Security
Help Net Security
Attack and Defense Labs
Attack and Defense Labs
N
Netflix TechBlog - Medium
Spread Privacy
Spread Privacy
F
Full Disclosure
Recorded Future
Recorded Future
AWS News Blog
AWS News Blog
博客园 - 【当耐特】
The Cloudflare Blog
T
Threatpost
T
Tor Project blog
Google DeepMind News
Google DeepMind News
C
CXSECURITY Database RSS Feed - CXSecurity.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
M
MIT News - Artificial intelligence
A
Arctic Wolf
C
Check Point Blog
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News - Newest:
Hacker News - Newest: "LLM"
WordPress大学
WordPress大学
Cyberwarzone
Cyberwarzone
小众软件
小众软件
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Proofpoint News Feed
Security Latest
Security Latest
The Last Watchdog
The Last Watchdog

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 Why I like go Speeding hexo (or any page) for PageSpeed insights Starting a blog with hexo and AWS S3
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!