Files
fn-serverless/api/agent/stats.go
Nigel Deakin 954f69e74a Add appname to basic metrics (#547)
* Add app labels to queued/running/completed/failed metrics

* Add app labels to queued/running/completed/failed metrics

* Add app labels to queued/running/completed/failed metrics
2017-11-28 10:17:24 -06:00

193 lines
4.1 KiB
Go

package agent
import (
"github.com/prometheus/client_golang/prometheus"
"sync"
)
// TODO this should expose:
// * hot containers active
// * memory used / available
// global statistics
type stats struct {
mu sync.Mutex
// statistics for all functions combined
queue uint64
running uint64
complete uint64
failed uint64
// statistics for individual functions, keyed by function path
functionStatsMap map[string]*functionStats
}
// statistics for an individual function
type functionStats struct {
queue uint64
running uint64
complete uint64
failed uint64
}
type Stats struct {
// statistics for all functions combined
Queue uint64
Running uint64
Complete uint64
Failed uint64
// statistics for individual functions, keyed by function path
FunctionStatsMap map[string]*FunctionStats
}
// statistics for an individual function
type FunctionStats struct {
Queue uint64
Running uint64
Complete uint64
Failed uint64
}
var (
fnQueued = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "fn_api_queued",
Help: "Queued requests by path",
},
[](string){"app", "path"},
)
fnRunning = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "fn_api_running",
Help: "Running requests by path",
},
[](string){"app", "path"},
)
fnCompleted = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "fn_api_completed",
Help: "Completed requests by path",
},
[](string){"app", "path"},
)
fnFailed = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "fn_api_failed",
Help: "Failed requests by path",
},
[](string){"app", "path"},
)
)
func init() {
prometheus.MustRegister(fnQueued)
prometheus.MustRegister(fnRunning)
prometheus.MustRegister(fnFailed)
prometheus.MustRegister(fnCompleted)
}
func (s *stats) getStatsForFunction(path string) *functionStats {
if s.functionStatsMap == nil {
s.functionStatsMap = make(map[string]*functionStats)
}
thisFunctionStats, found := s.functionStatsMap[path]
if !found {
thisFunctionStats = &functionStats{}
s.functionStatsMap[path] = thisFunctionStats
}
return thisFunctionStats
}
func (s *stats) Enqueue(app string, path string) {
s.mu.Lock()
s.queue++
s.getStatsForFunction(path).queue++
fnQueued.WithLabelValues(app, path).Inc()
s.mu.Unlock()
}
// Call when a function has been queued but cannot be started because of an error
func (s *stats) Dequeue(app string, path string) {
s.mu.Lock()
s.queue--
s.getStatsForFunction(path).queue--
fnQueued.WithLabelValues(app, path).Dec()
s.mu.Unlock()
}
func (s *stats) DequeueAndStart(app string, path string) {
s.mu.Lock()
s.queue--
s.getStatsForFunction(path).queue--
fnQueued.WithLabelValues(app, path).Dec()
s.running++
s.getStatsForFunction(path).running++
fnRunning.WithLabelValues(app, path).Inc()
s.mu.Unlock()
}
func (s *stats) Complete(app string, path string) {
s.mu.Lock()
s.running--
s.getStatsForFunction(path).running--
fnRunning.WithLabelValues(app, path).Dec()
s.complete++
s.getStatsForFunction(path).complete++
fnCompleted.WithLabelValues(app, path).Inc()
s.mu.Unlock()
}
func (s *stats) Failed(app string, path string) {
s.mu.Lock()
s.running--
s.getStatsForFunction(path).running--
fnRunning.WithLabelValues(app, path).Dec()
s.failed++
s.getStatsForFunction(path).failed++
fnFailed.WithLabelValues(app, path).Inc()
s.mu.Unlock()
}
func (s *stats) DequeueAndFail(app string, path string) {
s.mu.Lock()
s.queue--
s.getStatsForFunction(path).queue--
fnQueued.WithLabelValues(app, path).Dec()
s.failed++
s.getStatsForFunction(path).failed++
fnFailed.WithLabelValues(app, path).Inc()
s.mu.Unlock()
}
func (s *stats) Stats() Stats {
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
}
s.mu.Unlock()
return stats
}