etcd-io/etcd
Patterns and conventions
How etcd's Go code is organized, named, and exercised. Use this page as a quick reference when reading or writing code in the repository.
Module boundaries
The repo is a Go workspace (go.work) of independently-versioned modules. Each module has its own go.mod, go.sum, LICENSE, OWNERS, and a .gomodguard.yaml declaring which other modules and external dependencies it may import. make verify-gomodguard enforces this.
The high-level dependency direction is:
api -> (no etcd modules)
client/pkg -> (no etcd modules)
client/v3 -> api, client/pkg
pkg -> client/pkg, api
server -> api, client/pkg, client/v3 (limited), pkg
cache -> client/v3
etcdctl -> client/v3, pkg, etcdutl (snapshot only)
etcdutl -> server, api, client/pkg, pkg
tests -> everything (it's the integration boundary)If your change introduces a new edge between modules, it almost certainly needs a .gomodguard.yaml update.
Versioning suffixes
Most internal Go packages still use /v3 import paths reflecting the major version of the public API. Even modules that have moved to per-module tagging keep the import suffix for backwards compatibility, e.g. go.etcd.io/etcd/server/v3/etcdserver.
Logging
- Always use
*zap.Logger. The zero-value is forbidden — every constructor takes a logger or grabs one viaetcd.GetLogger(). nilloggers should be handled defensively for tests that don't pass one (see e.g.server/etcdserver/zap_raft.go).- Structured fields: prefer
zap.String("key", ...)overfmt.Sprintfinterpolation. - Logs that fire on every request should use
Debug.Infois reserved for state transitions (start, stop, leader change, snapshot finished).
Errors
- Sentinel errors are exported from each package (e.g.
mvcc.ErrCompacted,lease.ErrLeaseNotFound,auth.ErrPermissionDenied). - gRPC-facing errors are translated to
google.golang.org/grpc/statuscodes inserver/etcdserver/api/v3rpc/util.goandapi/v3/v3rpc/rpctypes/. - Use
errors.Is/errors.As. Wrapping withfmt.Errorf("...: %w", err)is the norm for new code.
Concurrency
- The server's serial sections are protected by named mutexes (
r.Lock(),s.applyW.Lock(), etc.) — read the file-level comments. go.etcd.io/etcd/pkg/v3/waitis the canonical "request id → response channel" map (used heavily inEtcdServer.processInternalRaftRequestOnce).- Long-running goroutines should listen on
s.stopping/s.doneand calls.goAttachto be tracked by the server's wait group.
Tracing
go.etcd.io/etcd/pkg/v3/traceutil provides a lightweight per-request trace structure that records named steps with timestamps. Production code attaches steps in hot paths (v3_server.go, apply/); the trace is dumped if total duration exceeds traceThreshold (100 ms).
OpenTelemetry tracing is opt-in (see debugging.md).
Feature gates
pkg/featuregate/ mirrors Kubernetes' feature-gate registry. Each gate has a name, a default, and a stability level (Alpha / Beta / GA). Gates are declared in server/features/etcd_features.go and surfaced via the --feature-gates flag (server/embed/config.go, ServerFeatureGateFlagName).
When adding a new behavior toggle, prefer a feature gate over a bespoke --experimental-* flag.
Protobuf
- Source
.protofiles live underapi/. - Regenerate with
scripts/genproto.sh(and verify withscripts/verify_genproto.sh). - Generated files end in
.pb.go,_grpc.pb.go,.pb.gw.go. Do not edit them by hand. - New gRPC methods need an
(google.api.http)annotation if they should be reachable via the REST gateway.
Testing
- Tests use Go's standard
testingpackage; no third-party assertion library globally — thoughgithub.com/stretchr/testifyis widely used. - Cluster fixtures are in
tests/framework/integration/cluster.go(multi-member in-process) andtests/framework/e2e/(subprocess). - Common workflow: write the test against the framework's
Clusterinterface (tests/framework/interfaces/), then it runs in both integration and e2e modes viatests/common/.
File header
Every Go file starts with the etcd Apache 2.0 header (./.header). make verify-lint will fail if the header is missing or wrong.
Naming
- Files:
lowercase_with_underscores.gois acceptable butlowercasewithoutseparators.gois more common. - Packages: short, lowercase, no separators.
mvcc,lease,rafthttp,etcdmain. - Functions: PascalCase exported, camelCase unexported, idiomatic Go.
- Mutex names: a comment above the mutex describing what it protects is mandatory in core packages.
Documentation comments
go.etcd.io/etcd/... is published on https://godocs.io. Any exported symbol must have a doc comment. The verify-lint step uses golangci-lint's revive rule (see tools/.golangci.yaml).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.