Skip to content

drpc: add Logger interface replacing Log callback and drpcdebug#57

Open
cthumuluru-crdb wants to merge 4 commits intocockroachdb:mainfrom
cthumuluru-crdb:drpc-logging
Open

drpc: add Logger interface replacing Log callback and drpcdebug#57
cthumuluru-crdb wants to merge 4 commits intocockroachdb:mainfrom
cthumuluru-crdb:drpc-logging

Conversation

@cthumuluru-crdb
Copy link
Copy Markdown

@cthumuluru-crdb cthumuluru-crdb commented May 6, 2026

Motivation

DRPC's logging has two problems:

  1. Options.Log func(error) is an error-only callback with no log-level differentiation, requiring nil-checks at every callsite.
  2. drpcdebug package provides build-tag-gated debug logging (-tags=debug) but is effectively dead code — no CI coverage, no tests, no active consumer. Last substantive change was in 2021.

This PR replaces both with a structured Logger interface (inspired by Pebble's logging pattern) and a new compile-time debug guard.

Changes

drpc.Logger interface

A four-method interface (Debugf, Infof, Errorf, Fatalf) in the top-level drpc package, alongside Handler, Conn, Transport, etc.

  • DefaultLoggerDebugf is a no-op; other levels log to stderr.
    Suitable for production out of the box.
  • InMemLogger — captures all output in memory for use in tests.

drpcserver: replace Log callback

Options.Log func(error) is replaced with Options.Logger. This is a breaking change — CockroachDB is the only consumer and is updated in a companion PR.

Logger propagation

Logger is threaded through Options in every package that emits log messages:

drpcserver → drpcmanager → drpcstream
                         → drpcwire.Writer
drpcclient (via DialOption) → drpcconn → drpcmanager → ...
drpcpool

Each constructor defaults opts.Logger to drpc.DefaultLogger if nil. No package stores a redundant copy — all access goes through opts.Logger.

drpcdebug package removed

The dead drpcdebug package is deleted. Its build-tag guard concept is preserved in a simpler form (see below).

Build-tag-gated debug logging

Debug log callsites sit on hot RPC paths (stream lifecycle, buffer flushes, packet reads). To guarantee zero cost in production, debug logging uses two layers of protection:

  1. Compile-time constantdrpc.DebugEnabled is a const bool defined in a pair of build-tagged files (debug_on.go / debug_off.go). When the constant is false, the compiler eliminates guarded blocks entirely.

  2. Callback pattern — log helpers take cb func() string instead of pre-formatted strings. Expensive formatting (fmt.Sprintf, .String()) is deferred and only evaluated when debug logging is compiled in.

func (m *Manager) log(what string, cb func() string) {
    if drpc.DebugEnabled {
        m.opts.Logger.Debugf("%s %s %s", m.String(), what, cb())
    }
}
Build DebugEnabled Debug blocks Callback allocation
go build false eliminated by compiler none
go build -tags=drpcdebug true active, routed through Logger evaluated on call

Infof, Errorf, and Fatalf are always active regardless of the build tag.

Running tests with debug logging

go test -tags=drpcdebug ./...

Companion PR

cockroachdb/cockroach#169813 — implements drpcLogger routing DRPC log output to CockroachDB's DEV channel and injects it into both server and client pool.

cthumuluru-crdb and others added 2 commits May 6, 2026 22:00
Today, DRPC has a fragile logging setup: the server takes a `Log func(error)`
callback for error reporting, and a build-tag-gated `drpcdebug` package for
operational tracing. The callback only supports errors (no levels), and the
debug logging is compile-time only with zero production usage.

Inspired by Pebble's Logger pattern, this commit introduces a proper Logger
interface with four log levels:

- Debugf: for verbose operational tracing (replaces drpcdebug in later commits)
- Infof: for general operational messages
- Errorf: for error conditions
- Fatalf: for unrecoverable errors

DefaultLogger logs Infof/Errorf/Fatalf to stderr via Go's stdlib log package,
while Debugf is a no-op to keep production quiet by default. Consumers like
CockroachDB can provide their own Logger implementation to route debug logs
through verbose/conditional logging systems.

InMemLogger captures all levels into an in-memory buffer for use in tests.

Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
The server's `Options.Log func(error)` was a limited error-only callback
that required nil-checks at every callsite and offered no log-level
differentiation. Replace it with the new `Logger` field, which defaults to
`drpc.DefaultLogger` when nil.

The two existing logging callsites in `Serve()` now use `Logger.Errorf`:
- temporary accept errors (with retry)
- client connection handler errors

This is a breaking API change. CockroachDB is the only consumer and will
be updated in a subsequent commit.

Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
@cthumuluru-crdb cthumuluru-crdb force-pushed the drpc-logging branch 2 times, most recently from 273dbe9 to dcb1977 Compare May 7, 2026 06:08
cthumuluru-crdb and others added 2 commits May 7, 2026 12:12
…pcpool

Thread the Logger interface through the entire DRPC stack so that all
packages have access to structured logging:

- drpcwire.Writer: add NewWriterWithLogger constructor, replace
  drpcdebug.Log calls with Logger.Debugf for buffer flush events.

- drpcstream.Options: add Logger field, default to drpc.DefaultLogger.
  Replace drpcdebug.Log calls with Logger.Debugf for stream lifecycle
  events (HANDLE, SEND, FIN, FLUSH, CALL).

- drpcmanager.Options: add Logger field, default to drpc.DefaultLogger.
  Replace drpcdebug.Log calls with Logger.Debugf for connection management
  events (WAIT, TERM, READ, STREAM, CANCEL, BUSY, UNFIN, CLEAN). Propagate
  Logger to Writer and Stream instances it creates.

- drpcpool.Options: add Logger field, default to drpc.DefaultLogger.
  Replace drpcdebug.Log calls with Logger.Debugf for pool operations
  (CLOSE, TAKEN, PUT).

- drpcserver: propagate its Logger to the managers it creates via
  ServeOne, ensuring the entire call stack shares the same logger.

All packages now use Logger.Debugf instead of the build-tag-gated
drpcdebug.Log. Since DefaultLogger.Debugf is a no-op, production behavior
is unchanged. Custom Logger implementations (e.g. CockroachDB's) can
route these to verbose/conditional logging.

Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
The drpcdebug package provided build-tag-gated debug logging that was
activated only when building with `-tags=debug`. Investigation shows it
was effectively dead code:

- No CI configuration or Makefile ever enabled the debug build tag
- No tests validated the debug-enabled code path
- CockroachDB (the primary consumer) never used it
- Last substantive change was in June 2021
- Only 4 callsites existed, all now replaced by Logger.Debugf

All functionality has been migrated to the Logger interface introduced
in the previous commits. The drpcdebug package is no longer imported
anywhere and can be safely deleted.

Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
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.

1 participant