mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 12:12:15 +08:00
167 lines
4.5 KiB
Go
167 lines
4.5 KiB
Go
package commands
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"runtime"
|
|
"runtime/trace"
|
|
"strconv"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
)
|
|
|
|
const (
|
|
profilingEnabledEnvName = "GF_DIAGNOSTICS_PROFILING_ENABLED"
|
|
profilingAddrEnvName = "GF_DIAGNOSTICS_PROFILING_ADDR"
|
|
profilingPortEnvName = "GF_DIAGNOSTICS_PROFILING_PORT"
|
|
profilingBlockRateEnvName = "GF_DIAGNOSTICS_PROFILING_BLOCK_RATE"
|
|
profilingMutexRateEnvName = "GF_DIAGNOSTICS_PROFILING_MUTEX_RATE"
|
|
tracingEnabledEnvName = "GF_DIAGNOSTICS_TRACING_ENABLED"
|
|
tracingFileEnvName = "GF_DIAGNOSTICS_TRACING_FILE"
|
|
)
|
|
|
|
type profilingDiagnostics struct {
|
|
enabled bool
|
|
addr string
|
|
port uint64
|
|
blockRate int
|
|
mutexRate int
|
|
}
|
|
|
|
func newProfilingDiagnostics(enabled bool, addr string, port uint64, blockRate int, mutexRate int) *profilingDiagnostics {
|
|
return &profilingDiagnostics{
|
|
enabled: enabled,
|
|
addr: addr,
|
|
port: port,
|
|
blockRate: blockRate,
|
|
mutexRate: mutexRate,
|
|
}
|
|
}
|
|
|
|
func (pd *profilingDiagnostics) overrideWithEnv() error {
|
|
enabledEnv := os.Getenv(profilingEnabledEnvName)
|
|
if enabledEnv != "" {
|
|
enabled, err := strconv.ParseBool(enabledEnv)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse %s environment variable as bool", profilingEnabledEnvName)
|
|
}
|
|
pd.enabled = enabled
|
|
}
|
|
|
|
addrEnv := os.Getenv(profilingAddrEnvName)
|
|
if addrEnv != "" {
|
|
pd.addr = addrEnv
|
|
}
|
|
|
|
portEnv := os.Getenv(profilingPortEnvName)
|
|
if portEnv != "" {
|
|
port, parseErr := strconv.ParseUint(portEnv, 0, 64)
|
|
if parseErr != nil {
|
|
return fmt.Errorf("failed to parse %s environment variable to unsigned integer", profilingPortEnvName)
|
|
}
|
|
pd.port = port
|
|
}
|
|
|
|
blockRateEnv := os.Getenv(profilingBlockRateEnvName)
|
|
if blockRateEnv != "" {
|
|
blockRate, err := strconv.Atoi(blockRateEnv)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse %s environment variable as int", profilingBlockRateEnvName)
|
|
}
|
|
pd.blockRate = blockRate
|
|
}
|
|
|
|
mutexFractionEnv := os.Getenv(profilingMutexRateEnvName)
|
|
if mutexFractionEnv != "" {
|
|
mutexProfileFraction, err := strconv.Atoi(mutexFractionEnv)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse %s environment variable as int", profilingMutexRateEnvName)
|
|
}
|
|
pd.mutexRate = mutexProfileFraction
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type tracingDiagnostics struct {
|
|
enabled bool
|
|
file string
|
|
}
|
|
|
|
func newTracingDiagnostics(enabled bool, file string) *tracingDiagnostics {
|
|
return &tracingDiagnostics{
|
|
enabled: enabled,
|
|
file: file,
|
|
}
|
|
}
|
|
|
|
func (td *tracingDiagnostics) overrideWithEnv() error {
|
|
enabledEnv := os.Getenv(tracingEnabledEnvName)
|
|
if enabledEnv != "" {
|
|
enabled, err := strconv.ParseBool(enabledEnv)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse %s environment variable as bool", tracingEnabledEnvName)
|
|
}
|
|
td.enabled = enabled
|
|
}
|
|
|
|
fileEnv := os.Getenv(tracingFileEnvName)
|
|
if fileEnv != "" {
|
|
td.file = fileEnv
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func setupProfiling(profile bool, profileAddr string, profilePort uint64, blockRate int, mutexFraction int) error {
|
|
profileDiagnostics := newProfilingDiagnostics(profile, profileAddr, profilePort, blockRate, mutexFraction)
|
|
if err := profileDiagnostics.overrideWithEnv(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if profileDiagnostics.enabled {
|
|
fmt.Println("diagnostics: pprof profiling enabled", "addr", profileDiagnostics.addr, "port", profileDiagnostics.port, "blockProfileRate", profileDiagnostics.blockRate, "mutexProfileRate", profileDiagnostics.mutexRate)
|
|
runtime.SetBlockProfileRate(profileDiagnostics.blockRate)
|
|
runtime.SetMutexProfileFraction(profileDiagnostics.mutexRate)
|
|
|
|
go func() {
|
|
// TODO: We should enable the linter and fix G114 here.
|
|
// G114: Use of net/http serve function that has no support for setting timeouts (gosec)
|
|
//
|
|
//nolint:gosec
|
|
err := http.ListenAndServe(fmt.Sprintf("%s:%d", profileDiagnostics.addr, profileDiagnostics.port), nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setupTracing(tracing bool, tracingFile string, logger *log.ConcreteLogger) error {
|
|
traceDiagnostics := newTracingDiagnostics(tracing, tracingFile)
|
|
if err := traceDiagnostics.overrideWithEnv(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if traceDiagnostics.enabled {
|
|
fmt.Println("diagnostics: tracing enabled", "file", traceDiagnostics.file)
|
|
f, err := os.Create(traceDiagnostics.file)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer func() {
|
|
if err := f.Close(); err != nil {
|
|
logger.Error("Failed to write trace diagnostics", "path", traceDiagnostics.file, "err", err)
|
|
}
|
|
}()
|
|
|
|
if err := trace.Start(f); err != nil {
|
|
panic(err)
|
|
}
|
|
defer trace.Stop()
|
|
}
|
|
return nil
|
|
}
|