diff --git a/.golangci.yml b/.golangci.yml index 38f21a3058..8af73f7126 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -122,6 +122,8 @@ linters-settings: disabled: true nestif: min-complexity: 17 + maintidx: + under: 10 godox: keywords: - BUG @@ -132,7 +134,7 @@ linters-settings: cyclop: max-complexity: 37 gocognit: - min-complexity: 53 + min-complexity: 63 gci: sections: - standard diff --git a/cmd/crictl/main.go b/cmd/crictl/main.go index 9924264928..bc63c2a8a4 100644 --- a/cmd/crictl/main.go +++ b/cmd/crictl/main.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "runtime" + "runtime/pprof" "slices" "sort" "strings" @@ -270,12 +271,42 @@ func main() { Usage: "Address to which the gRPC tracing collector will send spans to.", Value: "127.0.0.1:4317", }, + &cli.StringFlag{ + Name: "profile-cpu", + Usage: "Write a pprof CPU profile to the provided path.", + }, + &cli.StringFlag{ + Name: "profile-mem", + Usage: "Write a pprof memory profile to the provided path.", + }, } + var cpuProfile *os.File + defer func() { + if cpuProfile != nil { + pprof.StopCPUProfile() + cpuProfile.Close() + } + }() + app.Before = func(context *cli.Context) (err error) { var config *common.ServerConfiguration var exePath string + cpuProfilePath := context.String("profile-cpu") + if cpuProfilePath != "" { + logrus.Infof("Creating CPU profile in: %s", cpuProfilePath) + + cpuProfile, err = os.Create(cpuProfilePath) + if err != nil { + return fmt.Errorf("could not create CPU profile %q: %w", cpuProfilePath, err) + } + + if err := pprof.StartCPUProfile(cpuProfile); err != nil { + return fmt.Errorf("could not start CPU profiling in %q: %w", cpuProfilePath, err) + } + } + if exePath, err = os.Executable(); err != nil { logrus.Fatal(err) } @@ -355,6 +386,29 @@ func main() { return nil } + + app.After = func(ctx *cli.Context) error { + memProfilePath := ctx.String("profile-mem") + if memProfilePath != "" { + logrus.Infof("Creating memory profile in: %s", memProfilePath) + + file, err := os.Create(memProfilePath) + if err != nil { + return fmt.Errorf("could not create memory profile %q: %w", memProfilePath, err) + } + defer file.Close() + + // Ensure up to date data + runtime.GC() + + if err := pprof.WriteHeapProfile(file); err != nil { + return fmt.Errorf("could not write memory profile in %q: %w", memProfilePath, err) + } + } + + return nil + } + // sort all flags for _, cmd := range app.Commands { sort.Sort(cli.FlagsByName(cmd.Flags))