176 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package metrics
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	"github.com/prometheus/client_golang/prometheus"
 | 
						|
)
 | 
						|
 | 
						|
type Labels map[string]string
 | 
						|
 | 
						|
// NewNamespace returns a namespaces that is responsible for managing a collection of
 | 
						|
// metrics for a particual namespace and subsystem
 | 
						|
//
 | 
						|
// labels allows const labels to be added to all metrics created in this namespace
 | 
						|
// and are commonly used for data like application version and git commit
 | 
						|
func NewNamespace(name, subsystem string, labels Labels) *Namespace {
 | 
						|
	if labels == nil {
 | 
						|
		labels = make(map[string]string)
 | 
						|
	}
 | 
						|
	return &Namespace{
 | 
						|
		name:      name,
 | 
						|
		subsystem: subsystem,
 | 
						|
		labels:    labels,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Namespace describes a set of metrics that share a namespace and subsystem.
 | 
						|
type Namespace struct {
 | 
						|
	name      string
 | 
						|
	subsystem string
 | 
						|
	labels    Labels
 | 
						|
	mu        sync.Mutex
 | 
						|
	metrics   []prometheus.Collector
 | 
						|
}
 | 
						|
 | 
						|
// WithConstLabels returns a namespace with the provided set of labels merged
 | 
						|
// with the existing constant labels on the namespace.
 | 
						|
//
 | 
						|
//  Only metrics created with the returned namespace will get the new constant
 | 
						|
//  labels.  The returned namespace must be registered separately.
 | 
						|
func (n *Namespace) WithConstLabels(labels Labels) *Namespace {
 | 
						|
	n.mu.Lock()
 | 
						|
	ns := &Namespace{
 | 
						|
		name:      n.name,
 | 
						|
		subsystem: n.subsystem,
 | 
						|
		labels:    mergeLabels(n.labels, labels),
 | 
						|
	}
 | 
						|
	n.mu.Unlock()
 | 
						|
	return ns
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) NewCounter(name, help string) Counter {
 | 
						|
	c := &counter{pc: prometheus.NewCounter(n.newCounterOpts(name, help))}
 | 
						|
	n.Add(c)
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) NewLabeledCounter(name, help string, labels ...string) LabeledCounter {
 | 
						|
	c := &labeledCounter{pc: prometheus.NewCounterVec(n.newCounterOpts(name, help), labels)}
 | 
						|
	n.Add(c)
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) newCounterOpts(name, help string) prometheus.CounterOpts {
 | 
						|
	return prometheus.CounterOpts{
 | 
						|
		Namespace:   n.name,
 | 
						|
		Subsystem:   n.subsystem,
 | 
						|
		Name:        fmt.Sprintf("%s_%s", name, Total),
 | 
						|
		Help:        help,
 | 
						|
		ConstLabels: prometheus.Labels(n.labels),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) NewTimer(name, help string) Timer {
 | 
						|
	t := &timer{
 | 
						|
		m: prometheus.NewHistogram(n.newTimerOpts(name, help)),
 | 
						|
	}
 | 
						|
	n.Add(t)
 | 
						|
	return t
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) NewLabeledTimer(name, help string, labels ...string) LabeledTimer {
 | 
						|
	t := &labeledTimer{
 | 
						|
		m: prometheus.NewHistogramVec(n.newTimerOpts(name, help), labels),
 | 
						|
	}
 | 
						|
	n.Add(t)
 | 
						|
	return t
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) newTimerOpts(name, help string) prometheus.HistogramOpts {
 | 
						|
	return prometheus.HistogramOpts{
 | 
						|
		Namespace:   n.name,
 | 
						|
		Subsystem:   n.subsystem,
 | 
						|
		Name:        fmt.Sprintf("%s_%s", name, Seconds),
 | 
						|
		Help:        help,
 | 
						|
		ConstLabels: prometheus.Labels(n.labels),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) NewGauge(name, help string, unit Unit) Gauge {
 | 
						|
	g := &gauge{
 | 
						|
		pg: prometheus.NewGauge(n.newGaugeOpts(name, help, unit)),
 | 
						|
	}
 | 
						|
	n.Add(g)
 | 
						|
	return g
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) NewLabeledGauge(name, help string, unit Unit, labels ...string) LabeledGauge {
 | 
						|
	g := &labeledGauge{
 | 
						|
		pg: prometheus.NewGaugeVec(n.newGaugeOpts(name, help, unit), labels),
 | 
						|
	}
 | 
						|
	n.Add(g)
 | 
						|
	return g
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) newGaugeOpts(name, help string, unit Unit) prometheus.GaugeOpts {
 | 
						|
	return prometheus.GaugeOpts{
 | 
						|
		Namespace:   n.name,
 | 
						|
		Subsystem:   n.subsystem,
 | 
						|
		Name:        fmt.Sprintf("%s_%s", name, unit),
 | 
						|
		Help:        help,
 | 
						|
		ConstLabels: prometheus.Labels(n.labels),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) Describe(ch chan<- *prometheus.Desc) {
 | 
						|
	n.mu.Lock()
 | 
						|
	defer n.mu.Unlock()
 | 
						|
 | 
						|
	for _, metric := range n.metrics {
 | 
						|
		metric.Describe(ch)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) Collect(ch chan<- prometheus.Metric) {
 | 
						|
	n.mu.Lock()
 | 
						|
	defer n.mu.Unlock()
 | 
						|
 | 
						|
	for _, metric := range n.metrics {
 | 
						|
		metric.Collect(ch)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) Add(collector prometheus.Collector) {
 | 
						|
	n.mu.Lock()
 | 
						|
	n.metrics = append(n.metrics, collector)
 | 
						|
	n.mu.Unlock()
 | 
						|
}
 | 
						|
 | 
						|
func (n *Namespace) NewDesc(name, help string, unit Unit, labels ...string) *prometheus.Desc {
 | 
						|
	if string(unit) != "" {
 | 
						|
		name = fmt.Sprintf("%s_%s", name, unit)
 | 
						|
	}
 | 
						|
	namespace := n.name
 | 
						|
	if n.subsystem != "" {
 | 
						|
		namespace = fmt.Sprintf("%s_%s", namespace, n.subsystem)
 | 
						|
	}
 | 
						|
	name = fmt.Sprintf("%s_%s", namespace, name)
 | 
						|
	return prometheus.NewDesc(name, help, labels, prometheus.Labels(n.labels))
 | 
						|
}
 | 
						|
 | 
						|
// mergeLabels merges two or more labels objects into a single map, favoring
 | 
						|
// the later labels.
 | 
						|
func mergeLabels(lbs ...Labels) Labels {
 | 
						|
	merged := make(Labels)
 | 
						|
 | 
						|
	for _, target := range lbs {
 | 
						|
		for k, v := range target {
 | 
						|
			merged[k] = v
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return merged
 | 
						|
}
 |