Formalize Memory Monitoring
by extracting the interval and threshold into configuration options.
Related to f670b07e
.
This commit is contained in:
@ -85,8 +85,8 @@ func shutdownSentry() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initProfiling(options config.Profiling) (cancel func()) {
|
func initProfiling(options config.Profiling) (cancel func()) {
|
||||||
if options.Enabled {
|
if options.CPUEnabled {
|
||||||
profile, err := os.Create(options.File)
|
profile, err := os.Create(options.CPUFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Error while opening the profile file")
|
log.WithError(err).Error("Error while opening the profile file")
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ func initProfiling(options config.Profiling) (cancel func()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cancel = func() {
|
cancel = func() {
|
||||||
if options.Enabled {
|
if options.CPUEnabled {
|
||||||
log.Debug("Stopping CPU profiler")
|
log.Debug("Stopping CPU profiler")
|
||||||
pprof.StopCPUProfile()
|
pprof.StopCPUProfile()
|
||||||
if err := profile.Close(); err != nil {
|
if err := profile.Close(); err != nil {
|
||||||
@ -112,18 +112,20 @@ func initProfiling(options config.Profiling) (cancel func()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// watchMemoryAndAlert monitors the memory usage of Poseidon and sends an alert if it exceeds a threshold.
|
// watchMemoryAndAlert monitors the memory usage of Poseidon and sends an alert if it exceeds a threshold.
|
||||||
func watchMemoryAndAlert() {
|
func watchMemoryAndAlert(options config.Profiling) {
|
||||||
// We assume that Poseidon usually takes about 50-300 MB of memory. Therefore, we specify the threshold of 1 GB.
|
if options.MemoryInterval == 0 {
|
||||||
// Improve: Make this value dynamic or relative.
|
return
|
||||||
const threshold = 1 * 1000 * 1000 * 1000
|
}
|
||||||
const interval = 5 * time.Second
|
|
||||||
|
|
||||||
|
var exceeded bool
|
||||||
for {
|
for {
|
||||||
var stats runtime.MemStats
|
var stats runtime.MemStats
|
||||||
runtime.ReadMemStats(&stats)
|
runtime.ReadMemStats(&stats)
|
||||||
log.WithField("heap", stats.HeapAlloc).Trace("Current Memory Usage")
|
log.WithField("heap", stats.HeapAlloc).Trace("Current Memory Usage")
|
||||||
|
|
||||||
if stats.HeapAlloc >= threshold {
|
const megabytesToBytes = 1000 * 1000
|
||||||
|
if !exceeded && stats.HeapAlloc >= uint64(options.MemoryThreshold)*megabytesToBytes {
|
||||||
|
exceeded = true
|
||||||
log.WithField("heap", stats.HeapAlloc).Warn("Memory Threshold exceeded")
|
log.WithField("heap", stats.HeapAlloc).Warn("Memory Threshold exceeded")
|
||||||
|
|
||||||
err := pprof.Lookup("heap").WriteTo(os.Stderr, 1)
|
err := pprof.Lookup("heap").WriteTo(os.Stderr, 1)
|
||||||
@ -135,10 +137,13 @@ func watchMemoryAndAlert() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Warn("Failed to log the goroutines")
|
log.WithError(err).Warn("Failed to log the goroutines")
|
||||||
}
|
}
|
||||||
|
} else if exceeded {
|
||||||
|
exceeded = false
|
||||||
|
log.WithField("heap", stats.HeapAlloc).Info("Memory Threshold no longer exceeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(interval):
|
case <-time.After(time.Duration(options.MemoryInterval) * time.Millisecond):
|
||||||
continue
|
continue
|
||||||
case <-context.Background().Done():
|
case <-context.Background().Done():
|
||||||
return
|
return
|
||||||
@ -270,13 +275,13 @@ func main() {
|
|||||||
log.WithError(err).Warn("Could not initialize configuration")
|
log.WithError(err).Warn("Could not initialize configuration")
|
||||||
}
|
}
|
||||||
logging.InitializeLogging(config.Config.Logger.Level, config.Config.Logger.Formatter)
|
logging.InitializeLogging(config.Config.Logger.Level, config.Config.Logger.Formatter)
|
||||||
initSentry(&config.Config.Sentry, config.Config.Profiling.Enabled)
|
initSentry(&config.Config.Sentry, config.Config.Profiling.CPUEnabled)
|
||||||
|
|
||||||
cancelInflux := monitoring.InitializeInfluxDB(&config.Config.InfluxDB)
|
cancelInflux := monitoring.InitializeInfluxDB(&config.Config.InfluxDB)
|
||||||
defer cancelInflux()
|
defer cancelInflux()
|
||||||
|
|
||||||
stopProfiling := initProfiling(config.Config.Profiling)
|
stopProfiling := initProfiling(config.Config.Profiling)
|
||||||
go watchMemoryAndAlert()
|
go watchMemoryAndAlert(config.Config.Profiling)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
server := initServer(ctx)
|
server := initServer(ctx)
|
||||||
|
@ -64,10 +64,15 @@ logger:
|
|||||||
# Configuration of the embedded profiler
|
# Configuration of the embedded profiler
|
||||||
profiling:
|
profiling:
|
||||||
# Enables the runtime profiler
|
# Enables the runtime profiler
|
||||||
enabled: false
|
cpuenabled: false
|
||||||
# The file to which the profile is written to.
|
# The file to which the profile is written to.
|
||||||
# The default location `cmd/poseidon/default.pgo` will be picked up during the build process to create a profile-guided build.
|
# The default location `cmd/poseidon/default.pgo` will be picked up during the build process to create a profile-guided build.
|
||||||
file: cmd/poseidon/default.pgo
|
cpufile: cmd/poseidon/default.pgo
|
||||||
|
# If set, a memory watchdog will be started that monitors the memory usage of Poseidon and alerts if the threshold is exceeded.
|
||||||
|
# The value defines the interval in milliseconds in which the memory usage is checked.
|
||||||
|
memoryinterval: 30_000
|
||||||
|
# The Threshold in MB of memory usage at which Poseidon will start alerting.
|
||||||
|
memorythreshold: 1_000
|
||||||
|
|
||||||
# Configuration of the sentry logging
|
# Configuration of the sentry logging
|
||||||
sentry:
|
sentry:
|
||||||
|
@ -55,6 +55,9 @@ var (
|
|||||||
Level: "INFO",
|
Level: "INFO",
|
||||||
Formatter: dto.FormatterText,
|
Formatter: dto.FormatterText,
|
||||||
},
|
},
|
||||||
|
Profiling: Profiling{
|
||||||
|
MemoryThreshold: 1_000,
|
||||||
|
},
|
||||||
Sentry: sentry.ClientOptions{
|
Sentry: sentry.ClientOptions{
|
||||||
AttachStacktrace: true,
|
AttachStacktrace: true,
|
||||||
},
|
},
|
||||||
@ -130,8 +133,10 @@ type Logger struct {
|
|||||||
|
|
||||||
// Profiling configures the usage of a runtime profiler to create optimized binaries.
|
// Profiling configures the usage of a runtime profiler to create optimized binaries.
|
||||||
type Profiling struct {
|
type Profiling struct {
|
||||||
Enabled bool
|
CPUEnabled bool
|
||||||
File string
|
CPUFile string
|
||||||
|
MemoryInterval uint
|
||||||
|
MemoryThreshold uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// InfluxDB configures the usage of an Influx db monitoring.
|
// InfluxDB configures the usage of an Influx db monitoring.
|
||||||
|
Reference in New Issue
Block a user