mirror of
https://github.com/safing/portbase
synced 2025-09-05 04:00:14 +00:00
Merge pull request #158 from safing/feature/debug-apis-and-metrics-comment
Go profiling APIs and metrics comment
This commit is contained in:
commit
7797a54d18
3 changed files with 117 additions and 3 deletions
|
@ -2,10 +2,12 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/safing/portbase/utils/debug"
|
"github.com/safing/portbase/utils/debug"
|
||||||
)
|
)
|
||||||
|
@ -41,6 +43,42 @@ func registerDebugEndpoints() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := RegisterEndpoint(Endpoint{
|
||||||
|
Path: "debug/cpu",
|
||||||
|
Read: PermitAnyone,
|
||||||
|
DataFunc: handleCPUProfile,
|
||||||
|
Name: "Get CPU Profile",
|
||||||
|
Description: "",
|
||||||
|
Parameters: []Parameter{{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Field: "duration",
|
||||||
|
Value: "10s",
|
||||||
|
Description: "Specify the formatting style. The default is simple markdown formatting.",
|
||||||
|
}},
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RegisterEndpoint(Endpoint{
|
||||||
|
Path: "debug/heap",
|
||||||
|
Read: PermitAnyone,
|
||||||
|
DataFunc: handleHeapProfile,
|
||||||
|
Name: "Get Heap Profile",
|
||||||
|
Description: "",
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RegisterEndpoint(Endpoint{
|
||||||
|
Path: "debug/allocs",
|
||||||
|
Read: PermitAnyone,
|
||||||
|
DataFunc: handleAllocsProfile,
|
||||||
|
Name: "Get Allocs Profile",
|
||||||
|
Description: "",
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := RegisterEndpoint(Endpoint{
|
if err := RegisterEndpoint(Endpoint{
|
||||||
Path: "debug/info",
|
Path: "debug/info",
|
||||||
Read: PermitAnyone,
|
Read: PermitAnyone,
|
||||||
|
@ -90,6 +128,55 @@ func printStack(_ *Request) (msg string, err error) {
|
||||||
return "stack printed to stdout", nil
|
return "stack printed to stdout", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleCPUProfile returns the CPU profile.
|
||||||
|
func handleCPUProfile(ar *Request) (data []byte, err error) {
|
||||||
|
// Parse duration.
|
||||||
|
duration := 10 * time.Second
|
||||||
|
if durationOption := ar.Request.URL.Query().Get("duration"); durationOption != "" {
|
||||||
|
parsedDuration, err := time.ParseDuration(durationOption)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse duration: %w", err)
|
||||||
|
}
|
||||||
|
duration = parsedDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start CPU profiling.
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := pprof.StartCPUProfile(buf); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to start cpu profile: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the specified duration.
|
||||||
|
select {
|
||||||
|
case <-time.After(duration):
|
||||||
|
case <-ar.Context().Done():
|
||||||
|
pprof.StopCPUProfile()
|
||||||
|
return nil, context.Canceled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop CPU profiling and return data.
|
||||||
|
pprof.StopCPUProfile()
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleHeapProfile returns the Heap profile.
|
||||||
|
func handleHeapProfile(ar *Request) (data []byte, err error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := pprof.Lookup("heap").WriteTo(buf, 0); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to write heap profile: %w", err)
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleAllocsProfile returns the Allocs profile.
|
||||||
|
func handleAllocsProfile(ar *Request) (data []byte, err error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := pprof.Lookup("allocs").WriteTo(buf, 0); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to write allocs profile: %w", err)
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// debugInfo returns the debugging information for support requests.
|
// debugInfo returns the debugging information for support requests.
|
||||||
func debugInfo(ar *Request) (data []byte, err error) {
|
func debugInfo(ar *Request) (data []byte, err error) {
|
||||||
// Create debug information helper.
|
// Create debug information helper.
|
||||||
|
|
|
@ -14,13 +14,18 @@ var (
|
||||||
instanceOption config.StringOption
|
instanceOption config.StringOption
|
||||||
cfgOptionInstanceOrder = 0
|
cfgOptionInstanceOrder = 0
|
||||||
|
|
||||||
|
CfgOptionCommentKey = "core/metrics/comment"
|
||||||
|
commentOption config.StringOption
|
||||||
|
cfgOptionCommentOrder = 0
|
||||||
|
|
||||||
CfgOptionPushKey = "core/metrics/push"
|
CfgOptionPushKey = "core/metrics/push"
|
||||||
pushOption config.StringOption
|
pushOption config.StringOption
|
||||||
cfgOptionPushOrder = 0
|
cfgOptionPushOrder = 0
|
||||||
|
|
||||||
pushFlag string
|
|
||||||
instanceFlag string
|
instanceFlag string
|
||||||
defaultInstance string
|
defaultInstance string
|
||||||
|
commentFlag string
|
||||||
|
pushFlag string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -32,15 +37,16 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flag.StringVar(&instanceFlag, "metrics-instance", defaultInstance, "set the default metrics instance label for all metrics")
|
||||||
|
flag.StringVar(&commentFlag, "metrics-comment", "", "set the default metrics comment label")
|
||||||
flag.StringVar(&pushFlag, "push-metrics", "", "set default URL to push prometheus metrics to")
|
flag.StringVar(&pushFlag, "push-metrics", "", "set default URL to push prometheus metrics to")
|
||||||
flag.StringVar(&instanceFlag, "metrics-instance", defaultInstance, "set the default global instance label")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepConfig() error {
|
func prepConfig() error {
|
||||||
err := config.Register(&config.Option{
|
err := config.Register(&config.Option{
|
||||||
Name: "Metrics Instance Name",
|
Name: "Metrics Instance Name",
|
||||||
Key: CfgOptionInstanceKey,
|
Key: CfgOptionInstanceKey,
|
||||||
Description: "Define the prometheus instance label for exported metrics. Please note that changing the instance name will reset persisted metrics.",
|
Description: "Define the prometheus instance label for all exported metrics. Please note that changing the metrics instance name will reset persisted metrics.",
|
||||||
Sensitive: true,
|
Sensitive: true,
|
||||||
OptType: config.OptTypeString,
|
OptType: config.OptTypeString,
|
||||||
ExpertiseLevel: config.ExpertiseLevelExpert,
|
ExpertiseLevel: config.ExpertiseLevelExpert,
|
||||||
|
@ -58,6 +64,26 @@ func prepConfig() error {
|
||||||
}
|
}
|
||||||
instanceOption = config.Concurrent.GetAsString(CfgOptionInstanceKey, instanceFlag)
|
instanceOption = config.Concurrent.GetAsString(CfgOptionInstanceKey, instanceFlag)
|
||||||
|
|
||||||
|
err = config.Register(&config.Option{
|
||||||
|
Name: "Metrics Comment Label",
|
||||||
|
Key: CfgOptionCommentKey,
|
||||||
|
Description: "Define a metrics comment label, which is added to the info metric.",
|
||||||
|
Sensitive: true,
|
||||||
|
OptType: config.OptTypeString,
|
||||||
|
ExpertiseLevel: config.ExpertiseLevelExpert,
|
||||||
|
ReleaseLevel: config.ReleaseLevelStable,
|
||||||
|
DefaultValue: commentFlag,
|
||||||
|
RequiresRestart: true,
|
||||||
|
Annotations: config.Annotations{
|
||||||
|
config.DisplayOrderAnnotation: cfgOptionCommentOrder,
|
||||||
|
config.CategoryAnnotation: "Metrics",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
commentOption = config.Concurrent.GetAsString(CfgOptionCommentKey, commentFlag)
|
||||||
|
|
||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Push Prometheus Metrics",
|
Name: "Push Prometheus Metrics",
|
||||||
Key: CfgOptionPushKey,
|
Key: CfgOptionPushKey,
|
||||||
|
|
|
@ -23,6 +23,7 @@ func registerInfoMetric() error {
|
||||||
"go_arch": runtime.GOARCH,
|
"go_arch": runtime.GOARCH,
|
||||||
"go_version": runtime.Version(),
|
"go_version": runtime.Version(),
|
||||||
"go_compiler": runtime.Compiler,
|
"go_compiler": runtime.Compiler,
|
||||||
|
"comment": commentOption(),
|
||||||
},
|
},
|
||||||
func() float64 {
|
func() float64 {
|
||||||
return 1
|
return 1
|
||||||
|
|
Loading…
Add table
Reference in a new issue