metrics: add label type in metrics package
This commit is contained in:
parent
d87d697d92
commit
d77ebb8511
@ -95,6 +95,20 @@ func (exp *exp) getFloat(name string) *expvar.Float {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (exp *exp) getMap(name string) *expvar.Map {
|
||||||
|
var v *expvar.Map
|
||||||
|
exp.expvarLock.Lock()
|
||||||
|
p := expvar.Get(name)
|
||||||
|
if p != nil {
|
||||||
|
v = p.(*expvar.Map)
|
||||||
|
} else {
|
||||||
|
v = new(expvar.Map)
|
||||||
|
expvar.Publish(name, v)
|
||||||
|
}
|
||||||
|
exp.expvarLock.Unlock()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
func (exp *exp) publishCounter(name string, metric metrics.Counter) {
|
func (exp *exp) publishCounter(name string, metric metrics.Counter) {
|
||||||
v := exp.getInt(name)
|
v := exp.getInt(name)
|
||||||
v.Set(metric.Count())
|
v.Set(metric.Count())
|
||||||
@ -162,6 +176,60 @@ func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer
|
|||||||
exp.getInt(name + ".99-percentile").Set(ps[3])
|
exp.getInt(name + ".99-percentile").Set(ps[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (exp *exp) publishLabel(name string, metric metrics.Label) {
|
||||||
|
labels := metric.Value()
|
||||||
|
for k, v := range labels {
|
||||||
|
exp.getMap(name).Set(k, exp.interfaceToExpVal(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exp *exp) interfaceToExpVal(v interface{}) expvar.Var {
|
||||||
|
switch i := v.(type) {
|
||||||
|
case string:
|
||||||
|
newV := new(expvar.String)
|
||||||
|
newV.Set(i)
|
||||||
|
return newV
|
||||||
|
case int64:
|
||||||
|
newV := new(expvar.Int)
|
||||||
|
newV.Set(i)
|
||||||
|
return newV
|
||||||
|
case int32:
|
||||||
|
newV := new(expvar.Int)
|
||||||
|
newV.Set(int64(i))
|
||||||
|
return newV
|
||||||
|
case int16:
|
||||||
|
newV := new(expvar.Int)
|
||||||
|
newV.Set(int64(i))
|
||||||
|
return newV
|
||||||
|
case int8:
|
||||||
|
newV := new(expvar.Int)
|
||||||
|
newV.Set(int64(i))
|
||||||
|
return newV
|
||||||
|
case int:
|
||||||
|
newV := new(expvar.Int)
|
||||||
|
newV.Set(int64(i))
|
||||||
|
return newV
|
||||||
|
case float32:
|
||||||
|
newV := new(expvar.Float)
|
||||||
|
newV.Set(float64(i))
|
||||||
|
return newV
|
||||||
|
case float64:
|
||||||
|
newV := new(expvar.Float)
|
||||||
|
newV.Set(i)
|
||||||
|
return newV
|
||||||
|
case map[string]interface{}:
|
||||||
|
newV := new(expvar.Map)
|
||||||
|
for k, v := range i {
|
||||||
|
newV.Set(k, exp.interfaceToExpVal(v))
|
||||||
|
}
|
||||||
|
return newV
|
||||||
|
default:
|
||||||
|
newV := new(expvar.String)
|
||||||
|
newV.Set(fmt.Sprint(v))
|
||||||
|
return newV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (exp *exp) syncToExpvar() {
|
func (exp *exp) syncToExpvar() {
|
||||||
exp.registry.Each(func(name string, i interface{}) {
|
exp.registry.Each(func(name string, i interface{}) {
|
||||||
switch i := i.(type) {
|
switch i := i.(type) {
|
||||||
@ -179,6 +247,8 @@ func (exp *exp) syncToExpvar() {
|
|||||||
exp.publishTimer(name, i)
|
exp.publishTimer(name, i)
|
||||||
case metrics.ResettingTimer:
|
case metrics.ResettingTimer:
|
||||||
exp.publishResettingTimer(name, i)
|
exp.publishResettingTimer(name, i)
|
||||||
|
case metrics.Label:
|
||||||
|
exp.publishLabel(name, i)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
|
panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
|
||||||
}
|
}
|
||||||
|
48
metrics/label.go
Normal file
48
metrics/label.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
// Label hold an map[string]interface{} value that can be set arbitrarily.
|
||||||
|
type Label interface {
|
||||||
|
Value() map[string]interface{}
|
||||||
|
String() string
|
||||||
|
Mark(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegisteredLabel constructs and registers a new StandardLabel.
|
||||||
|
func NewRegisteredLabel(name string, r Registry) Label {
|
||||||
|
c := NewStandardLabel()
|
||||||
|
if nil == r {
|
||||||
|
r = DefaultRegistry
|
||||||
|
}
|
||||||
|
r.Register(name, c)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStandardLabel constructs a new StandardLabel.
|
||||||
|
func NewStandardLabel() *StandardLabel {
|
||||||
|
return &StandardLabel{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StandardLabel is the standard implementation of a Label.
|
||||||
|
type StandardLabel struct {
|
||||||
|
value map[string]interface{}
|
||||||
|
jsonStr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns label values.
|
||||||
|
func (l *StandardLabel) Value() map[string]interface{} {
|
||||||
|
return l.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark records the label.
|
||||||
|
func (l *StandardLabel) Mark(value map[string]interface{}) {
|
||||||
|
buf, _ := json.Marshal(value)
|
||||||
|
l.jsonStr = string(buf)
|
||||||
|
l.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns label by JSON format.
|
||||||
|
func (l *StandardLabel) String() string {
|
||||||
|
return l.jsonStr
|
||||||
|
}
|
@ -31,6 +31,7 @@ var (
|
|||||||
typeSummaryTpl = "# TYPE %s summary\n"
|
typeSummaryTpl = "# TYPE %s summary\n"
|
||||||
keyValueTpl = "%s %v\n\n"
|
keyValueTpl = "%s %v\n\n"
|
||||||
keyQuantileTagValueTpl = "%s {quantile=\"%s\"} %v\n"
|
keyQuantileTagValueTpl = "%s {quantile=\"%s\"} %v\n"
|
||||||
|
keyLabelValueTpl = "%s%s %v\n\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
// collector is a collection of byte buffers that aggregate Prometheus reports
|
// collector is a collection of byte buffers that aggregate Prometheus reports
|
||||||
@ -98,6 +99,15 @@ func (c *collector) addResettingTimer(name string, m metrics.ResettingTimer) {
|
|||||||
c.buff.WriteRune('\n')
|
c.buff.WriteRune('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *collector) addLabel(name string, m metrics.Label) {
|
||||||
|
c.writeLabel(mutateKey(name), m.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *collector) writeLabel(name string, value interface{}) {
|
||||||
|
c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
|
||||||
|
c.buff.WriteString(fmt.Sprintf(keyLabelValueTpl, name, value, 1))
|
||||||
|
}
|
||||||
|
|
||||||
func (c *collector) writeGaugeCounter(name string, value interface{}) {
|
func (c *collector) writeGaugeCounter(name string, value interface{}) {
|
||||||
name = mutateKey(name)
|
name = mutateKey(name)
|
||||||
c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
|
c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
|
||||||
|
@ -57,6 +57,8 @@ func Handler(reg metrics.Registry) http.Handler {
|
|||||||
c.addTimer(name, m.Snapshot())
|
c.addTimer(name, m.Snapshot())
|
||||||
case metrics.ResettingTimer:
|
case metrics.ResettingTimer:
|
||||||
c.addResettingTimer(name, m.Snapshot())
|
c.addResettingTimer(name, m.Snapshot())
|
||||||
|
case metrics.Label:
|
||||||
|
c.addLabel(name, m)
|
||||||
default:
|
default:
|
||||||
log.Warn("Unknown Prometheus metric type", "type", fmt.Sprintf("%T", i))
|
log.Warn("Unknown Prometheus metric type", "type", fmt.Sprintf("%T", i))
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ func (r *StandardRegistry) register(name string, i interface{}) error {
|
|||||||
return DuplicateMetric(name)
|
return DuplicateMetric(name)
|
||||||
}
|
}
|
||||||
switch i.(type) {
|
switch i.(type) {
|
||||||
case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer:
|
case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer, Label:
|
||||||
r.metrics[name] = i
|
r.metrics[name] = i
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user