-
Notifications
You must be signed in to change notification settings - Fork 18.7k
Description
Proposal: Add Hook/Interceptor for go Statement (Goroutine Start)
Abstract
This proposal suggests adding a mechanism to observe, log, or monitor every invocation of a goroutine via the go statement. This would allow developers to instrument goroutine creation for observability and debugging purposes, without needing to refactor codebases extensively.
Background & Motivation
Goroutines are a central feature of Go, offering lightweight concurrency. However, because go is a language keyword and not a function, there is no standard way to intercept or observe the spawning of goroutines.
The inability to intercept go calls limits:
- Runtime observability of concurrent behavior
- Accurate logging and tracing of goroutine life cycles
- Debugging tools that need visibility into all concurrent flows
- Runtime enforcement of policies related to goroutine usage (e.g., limits, tags, priorities, etc.)
Inspired by projects such as openshift-online/async-routine, this proposal aims to bring similar capabilities into the language or standard tooling in a first-class way.
Proposal
Introduce a mechanism—either at the language, compiler, or runtime level—that enables registering a hook function which is invoked on every goroutine creation.
The hook function might take the following form:
type GoroutineStartHook func(func())
func RegisterGoroutineStartHook(hook GoroutineStartHook)When registered, the Go runtime (or compiler-generated code) would wrap every goroutine call:
go func() {
// original code
}()Would behave as:
go runtime.invokeGoroutineStartHook(func() {
// original code
})Where invokeGoroutineStartHook would call the registered hook function, which can decide how to instrument, log, or even conditionally block execution.
Compatibility
- Backwards compatible: Existing code that doesn’t register a hook will behave exactly as today.
- Tooling-friendly: Hook registration could be used via build tags, environment variables, or initialization code in main packages.
Alternatives Considered
- Wrapping
gocalls manually in a helper function (Go(func())) — this does not scale and requires pervasive code changes. Does not work for 3rd party imports. - Static analysis or source code instrumentation — useful, but not as robust or flexible as runtime-level interception.
- Debuggers or profilers — provide observability but not programmable hooks or live instrumentation.
- Introduction of a new, experimental package, perhaps named
runtime/interceptor similar, that provides a mechanism to register a global interceptor function for go routine creation. If adopted, can be used as a standard mechinism to spawn go routines with the ability to intercept.
Use Cases
- Observability: Log every goroutine with context (file, line, stack).
- Tracing: Connect goroutine creation to a distributed trace.
- Debugging: Detect goroutines that never terminate or take too much time to execute.
- Security: Monitor or block goroutines based on policy.
Risks & Downsides
- Performance overhead: Every
gostatement incurs a hook invocation. This must be optional and optimized when disabled. - Complexity: Adds indirection to goroutine start-up, which must be minimal and well-tested.
- Semantic expectations: Developers may expect
goto be zero-cost. This breaks that assumption when hooks are enabled.
Prior Art
async-routine: Provides a wrapper around goroutines that enables timeboxing, observability, and monitoring.- JVM / CLR: Many managed runtimes allow thread start interception or instrumentation via AOP tools or runtime hooks.
Implementation Notes
The feature could be implemented at the compiler level (cmd/compile) by wrapping goroutine calls with a runtime dis