pkg/xcontext/metrics/simplemetrics/metrics.go (118 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
package simplemetrics
import (
"fmt"
"sort"
"strings"
"sync"
"github.com/facebookincubator/contest/pkg/xcontext/fields"
"github.com/facebookincubator/contest/pkg/xcontext/metrics"
)
type Fields = fields.Fields
type tags = fields.PendingFields
var _ metrics.Metrics = &Metrics{}
type storage struct {
locker sync.RWMutex
intGaugeFamilies map[string]*intGaugeFamily
gaugeFamilies map[string]*gaugeFamily
countFamilies map[string]*countFamily
}
// Metrics is a naive implementation of Metrics
type Metrics struct {
*storage
currentTags tags
}
// New returns an instance of Metrics.
func New() *Metrics {
return &Metrics{
storage: &storage{
intGaugeFamilies: make(map[string]*intGaugeFamily),
gaugeFamilies: make(map[string]*gaugeFamily),
countFamilies: make(map[string]*countFamily),
},
}
}
func tagsToString(tags tags) string {
m := tags.Compile()
tagStrings := make([]string, 0, len(m))
for key, value := range m {
tagStrings = append(tagStrings, strings.ReplaceAll(fmt.Sprintf("%s=%v", key, value), ",", "_"))
}
sort.Slice(tagStrings, func(i, j int) bool {
return tagStrings[i] < tagStrings[j]
})
return strings.Join(tagStrings, ",")
}
// Count returns Count.
//
// This method implements Metrics.
func (metrics *Metrics) Count(key string) metrics.Count {
metrics.storage.locker.RLock()
family := metrics.countFamilies[key]
metrics.storage.locker.RUnlock()
if family != nil {
return family.get(metrics.currentTags)
}
metrics.storage.locker.Lock()
defer metrics.storage.locker.Unlock()
family = metrics.countFamilies[key]
if family != nil {
return family.get(metrics.currentTags)
}
family = &countFamily{
Metrics: make(map[string]*Count),
}
metrics.countFamilies[key] = family
return family.get(metrics.currentTags)
}
// Gauge returns Gauge.
//
// This method implements Metrics.
func (metrics *Metrics) Gauge(key string) metrics.Gauge {
metrics.storage.locker.RLock()
family := metrics.gaugeFamilies[key]
metrics.storage.locker.RUnlock()
if family != nil {
return family.get(metrics.currentTags)
}
metrics.storage.locker.Lock()
defer metrics.storage.locker.Unlock()
family = metrics.gaugeFamilies[key]
if family != nil {
return family.get(metrics.currentTags)
}
family = &gaugeFamily{
Metrics: make(map[string]*Gauge),
}
metrics.gaugeFamilies[key] = family
return family.get(metrics.currentTags)
}
// IntGauge returns IntGauge.
//
// This method implements Metrics.
func (metrics *Metrics) IntGauge(key string) metrics.IntGauge {
metrics.storage.locker.RLock()
family := metrics.intGaugeFamilies[key]
metrics.storage.locker.RUnlock()
if family != nil {
return family.get(metrics.currentTags)
}
metrics.storage.locker.Lock()
defer metrics.storage.locker.Unlock()
family = metrics.intGaugeFamilies[key]
if family != nil {
return family.get(metrics.currentTags)
}
family = &intGaugeFamily{
Metrics: make(map[string]*IntGauge),
}
metrics.intGaugeFamilies[key] = family
return family.get(metrics.currentTags)
}
// WithTag returns a scope of Metrics with added field.
//
// This method implements Metrics.
func (metrics Metrics) WithTag(key string, value interface{}) metrics.Metrics {
if metrics.currentTags.Slice != nil {
metrics.currentTags.IsReadOnly = true
}
metrics.currentTags.AddOne(key, value)
return &metrics
}
// WithTags returns a scope of Metrics with added fields.
//
// This method implements Metrics.
func (metrics Metrics) WithTags(tags Fields) metrics.Metrics {
if tags == nil {
metrics.currentTags.IsReadOnly = false
metrics.currentTags.Slice = nil
return &metrics
}
if metrics.currentTags.Slice != nil {
metrics.currentTags.IsReadOnly = true
}
metrics.currentTags.AddMultiple(tags)
return &metrics
}