|
|
@@ -129,6 +129,23 @@ func RunServices(configJSON []byte) error {
|
|
|
}()
|
|
|
}
|
|
|
|
|
|
+ if config.RunPeriodicGarbageCollection() {
|
|
|
+ waitGroup.Add(1)
|
|
|
+ go func() {
|
|
|
+ waitGroup.Done()
|
|
|
+ ticker := time.NewTicker(time.Duration(config.PeriodicGarbageCollectionSeconds) * time.Second)
|
|
|
+ defer ticker.Stop()
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case <-shutdownBroadcast:
|
|
|
+ return
|
|
|
+ case <-ticker.C:
|
|
|
+ runtime.GC()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ }
|
|
|
+
|
|
|
if config.RunWebServer() {
|
|
|
waitGroup.Add(1)
|
|
|
go func() {
|
|
|
@@ -234,21 +251,35 @@ loop:
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
-func outputProcessProfiles(config *Config) {
|
|
|
+func getRuntimeMetrics() LogFields {
|
|
|
+
|
|
|
+ numGoroutine := runtime.NumGoroutine()
|
|
|
|
|
|
var memStats runtime.MemStats
|
|
|
runtime.ReadMemStats(&memStats)
|
|
|
- log.WithContextFields(
|
|
|
- LogFields{
|
|
|
- "num_goroutine": runtime.NumGoroutine(),
|
|
|
- "alloc": memStats.Alloc,
|
|
|
- "total_alloc": memStats.TotalAlloc,
|
|
|
- "sys": memStats.Sys,
|
|
|
- "pause_total_ns": memStats.PauseTotalNs,
|
|
|
- "pause_ns": memStats.PauseNs,
|
|
|
- "num_gc": memStats.NumGC,
|
|
|
- "gc_cpu_fraction": memStats.GCCPUFraction,
|
|
|
- }).Info("runtime_stats")
|
|
|
+
|
|
|
+ lastGC := ""
|
|
|
+ if memStats.LastGC > 0 {
|
|
|
+ lastGC = time.Unix(0, int64(memStats.LastGC)).UTC().Format(time.RFC3339)
|
|
|
+ }
|
|
|
+
|
|
|
+ return LogFields{
|
|
|
+ "num_goroutine": numGoroutine,
|
|
|
+ "heap_alloc": memStats.HeapAlloc,
|
|
|
+ "heap_sys": memStats.HeapSys,
|
|
|
+ "heap_idle": memStats.HeapIdle,
|
|
|
+ "heap_inuse": memStats.HeapInuse,
|
|
|
+ "heap_released": memStats.HeapReleased,
|
|
|
+ "heap_objects": memStats.HeapObjects,
|
|
|
+ "num_gc": memStats.NumGC,
|
|
|
+ "num_forced_gc": memStats.NumForcedGC,
|
|
|
+ "last_gc": lastGC,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func outputProcessProfiles(config *Config) {
|
|
|
+
|
|
|
+ log.WithContextFields(getRuntimeMetrics()).Info("runtime_metrics")
|
|
|
|
|
|
if config.ProcessProfileOutputDirectory != "" {
|
|
|
|
|
|
@@ -333,13 +364,15 @@ func logServerLoad(server *TunnelServer) {
|
|
|
|
|
|
protocolStats, regionStats := server.GetLoadStats()
|
|
|
|
|
|
- serverLoad := LogFields{
|
|
|
- "event_name": "server_load",
|
|
|
- }
|
|
|
+ serverLoad := getRuntimeMetrics()
|
|
|
+
|
|
|
+ serverLoad["event_name"] = "server_load"
|
|
|
+
|
|
|
+ serverLoad["establish_tunnels"] = server.GetEstablishTunnels()
|
|
|
+
|
|
|
for protocol, stats := range protocolStats {
|
|
|
serverLoad[protocol] = stats
|
|
|
}
|
|
|
- serverLoad["establish_tunnels"] = server.GetEstablishTunnels()
|
|
|
|
|
|
log.LogRawFieldsWithTimestamp(serverLoad)
|
|
|
|