2020-08-10 15:26:04 +02:00
package metrics
import (
"strings"
"sync"
"time"
"github.com/go-kit/kit/metrics"
"github.com/go-kit/kit/metrics/generic"
)
const (
2020-08-21 11:12:04 +02:00
// server meta information.
2020-08-10 15:26:04 +02:00
pilotConfigPrefix = "config"
pilotConfigReloadsTotalName = pilotConfigPrefix + "ReloadsTotal"
pilotConfigReloadsFailuresTotalName = pilotConfigPrefix + "ReloadsFailureTotal"
pilotConfigLastReloadSuccessName = pilotConfigPrefix + "LastReloadSuccess"
pilotConfigLastReloadFailureName = pilotConfigPrefix + "LastReloadFailure"
2020-08-21 11:12:04 +02:00
// entry point.
2020-08-10 15:26:04 +02:00
pilotEntryPointPrefix = "entrypoint"
pilotEntryPointReqsTotalName = pilotEntryPointPrefix + "RequestsTotal"
pilotEntryPointReqsTLSTotalName = pilotEntryPointPrefix + "RequestsTLSTotal"
pilotEntryPointReqDurationName = pilotEntryPointPrefix + "RequestDurationSeconds"
pilotEntryPointOpenConnsName = pilotEntryPointPrefix + "OpenConnections"
2020-08-21 11:12:04 +02:00
// service level.
2020-08-10 15:26:04 +02:00
pilotServicePrefix = "service"
pilotServiceReqsTotalName = pilotServicePrefix + "RequestsTotal"
pilotServiceReqsTLSTotalName = pilotServicePrefix + "RequestsTLSTotal"
pilotServiceReqDurationName = pilotServicePrefix + "RequestDurationSeconds"
pilotServiceOpenConnsName = pilotServicePrefix + "OpenConnections"
pilotServiceRetriesTotalName = pilotServicePrefix + "RetriesTotal"
pilotServiceServerUpName = pilotServicePrefix + "ServerUp"
)
const root = "value"
// RegisterPilot registers all Pilot metrics.
func RegisterPilot ( ) * PilotRegistry {
standardRegistry := & standardRegistry {
epEnabled : true ,
svcEnabled : true ,
}
pr := & PilotRegistry {
standardRegistry : standardRegistry ,
counters : make ( map [ string ] * pilotCounter ) ,
gauges : make ( map [ string ] * pilotGauge ) ,
histograms : make ( map [ string ] * pilotHistogram ) ,
}
standardRegistry . configReloadsCounter = pr . newCounter ( pilotConfigReloadsTotalName )
standardRegistry . configReloadsFailureCounter = pr . newCounter ( pilotConfigReloadsFailuresTotalName )
standardRegistry . lastConfigReloadSuccessGauge = pr . newGauge ( pilotConfigLastReloadSuccessName )
standardRegistry . lastConfigReloadFailureGauge = pr . newGauge ( pilotConfigLastReloadFailureName )
standardRegistry . entryPointReqsCounter = pr . newCounter ( pilotEntryPointReqsTotalName )
standardRegistry . entryPointReqsTLSCounter = pr . newCounter ( pilotEntryPointReqsTLSTotalName )
2020-09-18 15:36:04 +02:00
standardRegistry . entryPointReqDurationHistogram , _ = NewHistogramWithScale ( pr . newHistogram ( pilotEntryPointReqDurationName ) , time . Millisecond )
2020-08-10 15:26:04 +02:00
standardRegistry . entryPointOpenConnsGauge = pr . newGauge ( pilotEntryPointOpenConnsName )
standardRegistry . serviceReqsCounter = pr . newCounter ( pilotServiceReqsTotalName )
standardRegistry . serviceReqsTLSCounter = pr . newCounter ( pilotServiceReqsTLSTotalName )
2020-09-18 15:36:04 +02:00
standardRegistry . serviceReqDurationHistogram , _ = NewHistogramWithScale ( pr . newHistogram ( pilotServiceReqDurationName ) , time . Millisecond )
2020-08-10 15:26:04 +02:00
standardRegistry . serviceOpenConnsGauge = pr . newGauge ( pilotServiceOpenConnsName )
standardRegistry . serviceRetriesCounter = pr . newCounter ( pilotServiceRetriesTotalName )
standardRegistry . serviceServerUpGauge = pr . newGauge ( pilotServiceServerUpName )
return pr
}
// PilotMetric is a representation of a metric.
type PilotMetric struct {
Name string ` json:"name" `
Type string ` json:"type" `
Observations map [ string ] interface { } ` json:"observations" `
}
type pilotHistogramObservation struct {
Total float64 ` json:"total" `
Count float64 ` json:"count" `
}
// PilotRegistry represents the pilots metrics registry.
type PilotRegistry struct {
counters map [ string ] * pilotCounter
gauges map [ string ] * pilotGauge
histograms map [ string ] * pilotHistogram
* standardRegistry
}
// newCounter register and returns a new pilotCounter.
func ( pr * PilotRegistry ) newCounter ( name string ) * pilotCounter {
c := newPilotCounter ( name )
pr . counters [ name ] = c
return c
}
// newGauge register and returns a new pilotGauge.
func ( pr * PilotRegistry ) newGauge ( name string ) * pilotGauge {
g := newPilotGauge ( name )
pr . gauges [ name ] = g
return g
}
// newHistogram register and returns a new pilotHistogram.
func ( pr * PilotRegistry ) newHistogram ( name string ) * pilotHistogram {
h := newPilotHistogram ( name )
pr . histograms [ name ] = h
return h
}
// Data exports the metrics: metrics name -> labels -> values.
func ( pr * PilotRegistry ) Data ( ) [ ] PilotMetric {
var pilotMetrics [ ] PilotMetric
for name , counter := range pr . counters {
pilotMetric := PilotMetric {
Name : name ,
Type : "COUNTER" ,
Observations : make ( map [ string ] interface { } ) ,
}
pilotMetrics = append ( pilotMetrics , pilotMetric )
counter . counters . Range ( func ( key , value interface { } ) bool {
labels := key . ( string )
pc := value . ( * pilotCounter )
if labels == "" {
labels = root
}
if labels == root || len ( pc . c . LabelValues ( ) ) % 2 == 0 {
pilotMetric . Observations [ labels ] = pc . c . Value ( )
}
return true
} )
}
for name , gauge := range pr . gauges {
pilotMetric := PilotMetric {
Name : name ,
Type : "GAUGE" ,
Observations : make ( map [ string ] interface { } ) ,
}
pilotMetrics = append ( pilotMetrics , pilotMetric )
gauge . gauges . Range ( func ( key , value interface { } ) bool {
labels := key . ( string )
pg := value . ( * pilotGauge )
if labels == "" {
labels = root
}
if labels == root || len ( pg . g . LabelValues ( ) ) % 2 == 0 {
pilotMetric . Observations [ labels ] = pg . g . Value ( )
}
return true
} )
}
for name , histogram := range pr . histograms {
pilotMetric := PilotMetric {
Name : name ,
Type : "HISTOGRAM" ,
Observations : make ( map [ string ] interface { } ) ,
}
pilotMetrics = append ( pilotMetrics , pilotMetric )
histogram . histograms . Range ( func ( key , value interface { } ) bool {
labels := key . ( string )
ph := value . ( * pilotHistogram )
if labels == "" {
labels = root
}
if labels == root || len ( ph . labels ) % 2 == 0 {
pilotMetric . Observations [ labels ] = & pilotHistogramObservation {
Total : ph . total . Value ( ) ,
Count : ph . count . Value ( ) ,
}
}
return true
} )
}
return pilotMetrics
}
type pilotCounter struct {
c * generic . Counter
counters * sync . Map
}
func newPilotCounter ( name string ) * pilotCounter {
return & pilotCounter {
c : generic . NewCounter ( name ) ,
counters : & sync . Map { } ,
}
}
// With returns a new pilotCounter with the given labels.
func ( c * pilotCounter ) With ( labels ... string ) metrics . Counter {
newCounter := c . c . With ( labels ... ) . ( * generic . Counter )
newCounter . ValueReset ( )
return & pilotCounter {
c : newCounter ,
counters : c . counters ,
}
}
// Add adds the given delta to the counter.
func ( c * pilotCounter ) Add ( delta float64 ) {
labelsKey := strings . Join ( c . c . LabelValues ( ) , "," )
pc , _ := c . counters . LoadOrStore ( labelsKey , c )
pc . ( * pilotCounter ) . c . Add ( delta )
}
type pilotGauge struct {
g * generic . Gauge
gauges * sync . Map
}
func newPilotGauge ( name string ) * pilotGauge {
return & pilotGauge {
g : generic . NewGauge ( name ) ,
gauges : & sync . Map { } ,
}
}
// With returns a new pilotGauge with the given labels.
func ( g * pilotGauge ) With ( labels ... string ) metrics . Gauge {
newGauge := g . g . With ( labels ... ) . ( * generic . Gauge )
newGauge . Set ( 0 )
return & pilotGauge {
g : newGauge ,
gauges : g . gauges ,
}
}
// Set sets the given value to the gauge.
func ( g * pilotGauge ) Set ( value float64 ) {
labelsKey := strings . Join ( g . g . LabelValues ( ) , "," )
pg , _ := g . gauges . LoadOrStore ( labelsKey , g )
pg . ( * pilotGauge ) . g . Set ( value )
}
// Add adds the given delta to the gauge.
func ( g * pilotGauge ) Add ( delta float64 ) {
labelsKey := strings . Join ( g . g . LabelValues ( ) , "," )
pg , _ := g . gauges . LoadOrStore ( labelsKey , g )
pg . ( * pilotGauge ) . g . Add ( delta )
}
type pilotHistogram struct {
name string
labels [ ] string
count * generic . Counter
total * generic . Counter
histograms * sync . Map
}
func newPilotHistogram ( name string ) * pilotHistogram {
return & pilotHistogram {
name : name ,
labels : make ( [ ] string , 0 ) ,
count : & generic . Counter { } ,
total : & generic . Counter { } ,
histograms : & sync . Map { } ,
}
}
// With returns a new pilotHistogram with the given labels.
func ( h * pilotHistogram ) With ( labels ... string ) metrics . Histogram {
var newLabels [ ] string
newLabels = append ( newLabels , h . labels ... )
newLabels = append ( newLabels , labels ... )
return & pilotHistogram {
name : h . name ,
labels : newLabels ,
count : & generic . Counter { } ,
total : & generic . Counter { } ,
histograms : h . histograms ,
}
}
// Observe records a new value into the histogram.
func ( h * pilotHistogram ) Observe ( value float64 ) {
labelsKey := strings . Join ( h . labels , "," )
ph , _ := h . histograms . LoadOrStore ( labelsKey , h )
pHisto := ph . ( * pilotHistogram )
pHisto . count . Add ( 1 )
pHisto . total . Add ( value )
}