mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Cobra automatically displays usage messages, and also a gratuitous "Error: [...]" line in some cases, when any error at all occurs running a command. To suppress the usage message, you have to set cmd.SilenceUsage to true. But the code that would do this doesn't have access to it. To address this, we introduce a category of "usage error", implemented with stdlib error wrapping (%w) and use errors.Is to check for it. There's also utility functions to do this checking automatically, or indeed, to handle wrapping of the ctl.SomethingCommand and handle running it with a suitable context and everything. In fact, several of the places we're checking for usage errors, we can never actually report one, but we're checking consistently so that if we want to report usage errors, we can. For instance, server.Start and (dax)server.Start don't ever return usage errors, right now, but we're checking their responses anyway.
64 lines
1.7 KiB
Go
64 lines
1.7 KiB
Go
package ctl
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/http"
|
|
"net/http/pprof"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/felixge/fgprof"
|
|
"github.com/molecula/featurebase/v3/logger"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type ctlUsageError struct{}
|
|
|
|
func (c ctlUsageError) Error() string {
|
|
return "usage error"
|
|
}
|
|
|
|
var UsageError ctlUsageError
|
|
|
|
// startProfilingServer starts a server which handles /debug/pprof and
|
|
// /debug/fgprof for use in utilities we might want to profile but
|
|
// wouldn't otherwise be running an http server. Caller should call
|
|
// the returned close function before exiting to release resources.
|
|
func startProfilingServer(addr string, logger logger.Logger) (close func() error, err error) {
|
|
if addr == "" {
|
|
return func() error { return nil }, nil
|
|
}
|
|
|
|
sm := http.NewServeMux()
|
|
sm.Handle("/debug/fgprof", fgprof.Handler())
|
|
sm.HandleFunc("/debug/pprof/", pprof.Index)
|
|
sm.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
|
sm.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
|
sm.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
|
sm.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
|
s := &http.Server{
|
|
Addr: addr,
|
|
Handler: sm,
|
|
}
|
|
runtime.SetBlockProfileRate(10000000) // 1 sample per 10 ms
|
|
runtime.SetMutexProfileFraction(100) // 1% sampling
|
|
ln, err := net.Listen("tcp", addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
go func() {
|
|
logger.Printf("Listening for /debug/pprof/ and /debug/fgprof on '%s'", ln.Addr().String())
|
|
logger.Printf("%v", s.Serve(ln))
|
|
}()
|
|
|
|
return func() error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
defer cancel()
|
|
err := s.Shutdown(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "shutting down profiling server")
|
|
}
|
|
return s.Close()
|
|
}, nil
|
|
}
|