mirror of
https://github.com/zrepl/zrepl.git
synced 2025-08-15 01:22:26 +02:00
[#307] add package trace, integrate it with logging, and adopt it throughout zrepl
package trace: - introduce the concept of tasks and spans, tracked as linked list within ctx - see package-level docs for an overview of the concepts - **main feature 1**: unique stack of task and span IDs - makes it easy to follow a series of log entries in concurrent code - **main feature 2**: ability to produce a chrome://tracing-compatible trace file - either via an env variable or a `zrepl pprof` subcommand - this is not a CPU profile, we already have go pprof for that - but it is very useful to visually inspect where the replication / snapshotter / pruner spends its time ( fixes #307 ) usage in package daemon/logging: - goal: every log entry should have a trace field with the ID stack from package trace - make `logging.GetLogger(ctx, Subsys)` the authoritative `logger.Logger` factory function - the context carries a linked list of injected fields which `logging.GetLogger` adds to the logger it returns - `logging.GetLogger` also uses package `trace` to get the task-and-span-stack and injects it into the returned logger's fields
This commit is contained in:
@ -33,16 +33,33 @@ type Handler interface {
|
||||
|
||||
type Logger = logger.Logger
|
||||
|
||||
type ContextInterceptorData interface {
|
||||
FullMethod() string
|
||||
ClientIdentity() string
|
||||
}
|
||||
|
||||
type ContextInterceptor = func(ctx context.Context, data ContextInterceptorData, handler func(ctx context.Context))
|
||||
|
||||
type Server struct {
|
||||
h Handler
|
||||
wi WireInterceptor
|
||||
ci ContextInterceptor
|
||||
log Logger
|
||||
}
|
||||
|
||||
func NewServer(wi WireInterceptor, logger Logger, handler Handler) *Server {
|
||||
var noopContextInteceptor = func(ctx context.Context, _ ContextInterceptorData, handler func(context.Context)) {
|
||||
handler(ctx)
|
||||
}
|
||||
|
||||
// wi and ci may be nil
|
||||
func NewServer(wi WireInterceptor, ci ContextInterceptor, logger Logger, handler Handler) *Server {
|
||||
if ci == nil {
|
||||
ci = noopContextInteceptor
|
||||
}
|
||||
return &Server{
|
||||
h: handler,
|
||||
wi: wi,
|
||||
ci: ci,
|
||||
log: logger,
|
||||
}
|
||||
}
|
||||
@ -93,6 +110,14 @@ func (s *Server) Serve(ctx context.Context, l transport.AuthenticatedListener) {
|
||||
}
|
||||
}
|
||||
|
||||
type contextInterceptorData struct {
|
||||
fullMethod string
|
||||
clientIdentity string
|
||||
}
|
||||
|
||||
func (d contextInterceptorData) FullMethod() string { return d.fullMethod }
|
||||
func (d contextInterceptorData) ClientIdentity() string { return d.clientIdentity }
|
||||
|
||||
func (s *Server) serveConn(nc *transport.AuthConn) {
|
||||
s.log.Debug("serveConn begin")
|
||||
defer s.log.Debug("serveConn done")
|
||||
@ -117,6 +142,17 @@ func (s *Server) serveConn(nc *transport.AuthConn) {
|
||||
}
|
||||
endpoint := string(header)
|
||||
|
||||
data := contextInterceptorData{
|
||||
fullMethod: endpoint,
|
||||
clientIdentity: nc.ClientIdentity(),
|
||||
}
|
||||
s.ci(ctx, data, func(ctx context.Context) {
|
||||
s.serveConnRequest(ctx, endpoint, c)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) serveConnRequest(ctx context.Context, endpoint string, c *stream.Conn) {
|
||||
|
||||
reqStructured, err := c.ReadStreamedMessage(ctx, RequestStructuredMaxSize, ReqStructured)
|
||||
if err != nil {
|
||||
s.log.WithError(err).Error("error reading structured part")
|
||||
|
Reference in New Issue
Block a user