diff --git a/api/agent/stats.go b/api/agent/stats.go index eacd1af44..5246645b7 100644 --- a/api/agent/stats.go +++ b/api/agent/stats.go @@ -10,62 +10,85 @@ import ( // * hot containers active // * memory used / available -// global statistics +// stats is the top-level struct containing composite and individial statistics all routes in all apps +// an instance of this struc is maintained in memory to keep a record of the current stats since the server was started +// access must be synchronized using the Mutex type stats struct { mu sync.Mutex - // statistics for all functions combined + // composite statistics for all routes in all apps queue uint64 running uint64 complete uint64 failed uint64 - // statistics for individual functions, keyed by function path - functionStatsMap map[string]*functionStats + // statistics for individual apps, keyed by appname + apps map[string]appStats } -// statistics for an individual function -type functionStats struct { +// appStats holds statistics for the routes in an individual app, keyed by the path of the route +// instances of this struc are used to maintain an in-memory record of the current stats +// access must be synchronized using the Mutex on the parent stats +type appStats struct { + routes map[string]*routeStats +} + +// routeStats holds statistics for an individual route +// instances of this struc are used to maintain an in-memory record of the current stats +// access must be synchronized using the Mutex on the parent stats +type routeStats struct { queue uint64 running uint64 complete uint64 failed uint64 } -// Stats hold the statistics for all functions combined -// and the statistics for each individual function +// Stats is the top-level struct containing composite and individial statistics all routes in all apps +// an instance of this struc is created when converting the current stats to JSON type Stats struct { Queue uint64 Running uint64 Complete uint64 Failed uint64 - // statistics for individual functions, keyed by function path - FunctionStatsMap map[string]*FunctionStats + // statistics for individual apps, keyed by appname + Apps map[string]AppStats } -// FunctionStats holds the statistics for an individual function -type FunctionStats struct { +// AppStats holds statistics for the routes in an individual app, keyed by the path of the route +// instances of this struc are used when converting the current stats to JSON +type AppStats struct { + Routes map[string]*RouteStats +} + +// RouteStats holds statistics for an individual route +// instances of this struc are used when converting the current stats to JSON +type RouteStats struct { Queue uint64 Running uint64 Complete uint64 Failed uint64 } -func (s *stats) getStatsForFunction(path string) *functionStats { - if s.functionStatsMap == nil { - s.functionStatsMap = make(map[string]*functionStats) +// return the stats corresponding to the specified app name and route path, creating a new stats if one does not already exist +func (s *stats) getStatsForRoute(app string, path string) *routeStats { + if s.apps == nil { + s.apps = make(map[string]appStats) } - thisFunctionStats, found := s.functionStatsMap[path] - if !found { - thisFunctionStats = &functionStats{} - s.functionStatsMap[path] = thisFunctionStats + thisAppStats, appFound := s.apps[app] + if !appFound { + thisAppStats = appStats{routes: make(map[string]*routeStats)} + s.apps[app] = thisAppStats } - - return thisFunctionStats + thisRouteStats, pathFound := thisAppStats.routes[path] + if !pathFound { + thisRouteStats = &routeStats{} + thisAppStats.routes[path] = thisRouteStats + } + return thisRouteStats } func (s *stats) Enqueue(ctx context.Context, app string, path string) { s.mu.Lock() - fstats := s.getStatsForFunction(path) + fstats := s.getStatsForRoute(app, path) s.queue++ fstats.queue++ @@ -79,7 +102,7 @@ func (s *stats) Enqueue(ctx context.Context, app string, path string) { func (s *stats) Dequeue(ctx context.Context, app string, path string) { s.mu.Lock() - fstats := s.getStatsForFunction(path) + fstats := s.getStatsForRoute(app, path) s.queue-- fstats.queue-- @@ -91,7 +114,7 @@ func (s *stats) Dequeue(ctx context.Context, app string, path string) { func (s *stats) DequeueAndStart(ctx context.Context, app string, path string) { s.mu.Lock() - fstats := s.getStatsForFunction(path) + fstats := s.getStatsForRoute(app, path) s.queue-- s.running++ fstats.queue-- @@ -106,7 +129,7 @@ func (s *stats) DequeueAndStart(ctx context.Context, app string, path string) { func (s *stats) Complete(ctx context.Context, app string, path string) { s.mu.Lock() - fstats := s.getStatsForFunction(path) + fstats := s.getStatsForRoute(app, path) s.running-- s.complete++ fstats.running-- @@ -121,7 +144,7 @@ func (s *stats) Complete(ctx context.Context, app string, path string) { func (s *stats) Failed(ctx context.Context, app string, path string) { s.mu.Lock() - fstats := s.getStatsForFunction(path) + fstats := s.getStatsForRoute(app, path) s.running-- s.failed++ fstats.running-- @@ -136,7 +159,7 @@ func (s *stats) Failed(ctx context.Context, app string, path string) { func (s *stats) DequeueAndFail(ctx context.Context, app string, path string) { s.mu.Lock() - fstats := s.getStatsForFunction(path) + fstats := s.getStatsForRoute(app, path) s.queue-- s.failed++ fstats.queue-- @@ -161,16 +184,22 @@ func IncrementTooBusy(ctx context.Context) { } func (s *stats) Stats() Stats { + // this creates a Stats from a stats + // stats is the internal struc which is continuously updated, and access is controlled using its Mutex + // Stats is a deep copy for external use, and can be converted to JSON var stats Stats s.mu.Lock() stats.Running = s.running stats.Complete = s.complete stats.Queue = s.queue stats.Failed = s.failed - stats.FunctionStatsMap = make(map[string]*FunctionStats) - for key, value := range s.functionStatsMap { - thisFunctionStats := &FunctionStats{Queue: value.queue, Running: value.running, Complete: value.complete, Failed: value.failed} - stats.FunctionStatsMap[key] = thisFunctionStats + stats.Apps = make(map[string]AppStats) + for appname, thisAppStats := range s.apps { + newAppStats := AppStats{Routes: make(map[string]*RouteStats)} + stats.Apps[appname] = newAppStats + for path, thisRouteStats := range thisAppStats.routes { + newAppStats.Routes[path] = &RouteStats{Queue: thisRouteStats.queue, Running: thisRouteStats.running, Complete: thisRouteStats.complete, Failed: thisRouteStats.failed} + } } s.mu.Unlock() return stats