forked from mirrors/statsd_exporter
Merge pull request #363 from glightfoot/cache-interface
Better mapper cache interface
This commit is contained in:
commit
12281a972e
13 changed files with 395 additions and 274 deletions
|
@ -572,7 +572,7 @@ func TestHandlePacket(t *testing.T) {
|
||||||
le := len(events)
|
le := len(events)
|
||||||
// Flatten actual events.
|
// Flatten actual events.
|
||||||
actual := event.Events{}
|
actual := event.Events{}
|
||||||
for i := 0; i < le; i++ {
|
for j := 0; j < le; j++ {
|
||||||
actual = append(actual, <-events...)
|
actual = append(actual, <-events...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,7 +650,7 @@ mappings:
|
||||||
`
|
`
|
||||||
// Create mapper from config and start an Exporter with a synchronous channel
|
// Create mapper from config and start an Exporter with a synchronous channel
|
||||||
testMapper := &mapper.MetricMapper{}
|
testMapper := &mapper.MetricMapper{}
|
||||||
err := testMapper.InitFromYAMLString(config, 0)
|
err := testMapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Config load error: %s %s", config, err)
|
t.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/go-kit/kit/log"
|
"github.com/go-kit/kit/log"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
"github.com/prometheus/statsd_exporter/pkg/event"
|
"github.com/prometheus/statsd_exporter/pkg/event"
|
||||||
"github.com/prometheus/statsd_exporter/pkg/exporter"
|
"github.com/prometheus/statsd_exporter/pkg/exporter"
|
||||||
"github.com/prometheus/statsd_exporter/pkg/line"
|
"github.com/prometheus/statsd_exporter/pkg/line"
|
||||||
|
@ -167,7 +168,7 @@ mappings:
|
||||||
`
|
`
|
||||||
|
|
||||||
testMapper := &mapper.MetricMapper{}
|
testMapper := &mapper.MetricMapper{}
|
||||||
err := testMapper.InitFromYAMLString(config, 0)
|
err := testMapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
|
58
main.go
58
main.go
|
@ -39,6 +39,8 @@ import (
|
||||||
"github.com/prometheus/statsd_exporter/pkg/line"
|
"github.com/prometheus/statsd_exporter/pkg/line"
|
||||||
"github.com/prometheus/statsd_exporter/pkg/listener"
|
"github.com/prometheus/statsd_exporter/pkg/listener"
|
||||||
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache/lru"
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache/randomreplacement"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -206,7 +208,7 @@ func serveHTTP(mux http.Handler, listenAddress string, logger log.Logger) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sighupConfigReloader(fileName string, mapper *mapper.MetricMapper, cacheSize int, logger log.Logger, option mapper.CacheOption) {
|
func sighupConfigReloader(fileName string, mapper *mapper.MetricMapper, logger log.Logger) {
|
||||||
signals := make(chan os.Signal, 1)
|
signals := make(chan os.Signal, 1)
|
||||||
signal.Notify(signals, syscall.SIGHUP)
|
signal.Notify(signals, syscall.SIGHUP)
|
||||||
|
|
||||||
|
@ -218,12 +220,12 @@ func sighupConfigReloader(fileName string, mapper *mapper.MetricMapper, cacheSiz
|
||||||
|
|
||||||
level.Info(logger).Log("msg", "Received signal, attempting reload", "signal", s)
|
level.Info(logger).Log("msg", "Received signal, attempting reload", "signal", s)
|
||||||
|
|
||||||
reloadConfig(fileName, mapper, cacheSize, logger, option)
|
reloadConfig(fileName, mapper, logger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reloadConfig(fileName string, mapper *mapper.MetricMapper, cacheSize int, logger log.Logger, option mapper.CacheOption) {
|
func reloadConfig(fileName string, mapper *mapper.MetricMapper, logger log.Logger) {
|
||||||
err := mapper.InitFromFile(fileName, cacheSize, option)
|
err := mapper.InitFromFile(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Info(logger).Log("msg", "Error reloading config", "error", err)
|
level.Info(logger).Log("msg", "Error reloading config", "error", err)
|
||||||
configLoads.WithLabelValues("failure").Inc()
|
configLoads.WithLabelValues("failure").Inc()
|
||||||
|
@ -247,6 +249,29 @@ func dumpFSM(mapper *mapper.MetricMapper, dumpFilename string, logger log.Logger
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCache(cacheSize int, cacheType string, registerer prometheus.Registerer) (mapper.MetricMapperCache, error) {
|
||||||
|
var cache mapper.MetricMapperCache
|
||||||
|
var err error
|
||||||
|
if cacheSize == 0 {
|
||||||
|
return nil, nil
|
||||||
|
} else {
|
||||||
|
switch cacheType {
|
||||||
|
case "lru":
|
||||||
|
cache, err = lru.NewMetricMapperLRUCache(registerer, cacheSize)
|
||||||
|
case "random":
|
||||||
|
cache, err = randomreplacement.NewMetricMapperRRCache(registerer, cacheSize)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unsupported cache type %q", cacheType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache, nil
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
listenAddress = kingpin.Flag("web.listen-address", "The address on which to expose the web interface and generated Prometheus metrics.").Default(":9102").String()
|
listenAddress = kingpin.Flag("web.listen-address", "The address on which to expose the web interface and generated Prometheus metrics.").Default(":9102").String()
|
||||||
|
@ -293,8 +318,6 @@ func main() {
|
||||||
parser.EnableSignalFXParsing()
|
parser.EnableSignalFXParsing()
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheOption := mapper.WithCacheType(*cacheType)
|
|
||||||
|
|
||||||
level.Info(logger).Log("msg", "Starting StatsD -> Prometheus Exporter", "version", version.Info())
|
level.Info(logger).Log("msg", "Starting StatsD -> Prometheus Exporter", "version", version.Info())
|
||||||
level.Info(logger).Log("msg", "Build context", "context", version.BuildContext())
|
level.Info(logger).Log("msg", "Build context", "context", version.BuildContext())
|
||||||
|
|
||||||
|
@ -302,15 +325,23 @@ func main() {
|
||||||
defer close(events)
|
defer close(events)
|
||||||
eventQueue := event.NewEventQueue(events, *eventFlushThreshold, *eventFlushInterval, eventsFlushed)
|
eventQueue := event.NewEventQueue(events, *eventFlushThreshold, *eventFlushInterval, eventsFlushed)
|
||||||
|
|
||||||
mapper := &mapper.MetricMapper{Registerer: prometheus.DefaultRegisterer, MappingsCount: mappingsCount}
|
thisMapper := &mapper.MetricMapper{Registerer: prometheus.DefaultRegisterer, MappingsCount: mappingsCount}
|
||||||
|
|
||||||
|
cache, err := getCache(*cacheSize, *cacheType, thisMapper.Registerer)
|
||||||
|
if err != nil {
|
||||||
|
level.Error(logger).Log("msg", "Unable to setup metric mapper cache", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
thisMapper.UseCache(cache)
|
||||||
|
|
||||||
if *mappingConfig != "" {
|
if *mappingConfig != "" {
|
||||||
err := mapper.InitFromFile(*mappingConfig, *cacheSize, cacheOption)
|
err := thisMapper.InitFromFile(*mappingConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(logger).Log("msg", "error loading config", "error", err)
|
level.Error(logger).Log("msg", "error loading config", "error", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if *dumpFSMPath != "" {
|
if *dumpFSMPath != "" {
|
||||||
err := dumpFSM(mapper, *dumpFSMPath, logger)
|
err := dumpFSM(thisMapper, *dumpFSMPath, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(logger).Log("msg", "error dumping FSM", "error", err)
|
level.Error(logger).Log("msg", "error dumping FSM", "error", err)
|
||||||
// Failure to dump the FSM is an error (the user asked for it and it
|
// Failure to dump the FSM is an error (the user asked for it and it
|
||||||
|
@ -318,11 +349,9 @@ func main() {
|
||||||
// afterwards).
|
// afterwards).
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
mapper.InitCache(*cacheSize, cacheOption)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exporter := exporter.NewExporter(prometheus.DefaultRegisterer, mapper, logger, eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
exporter := exporter.NewExporter(prometheus.DefaultRegisterer, thisMapper, logger, eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
||||||
|
|
||||||
if *checkConfig {
|
if *checkConfig {
|
||||||
level.Info(logger).Log("msg", "Configuration check successful, exiting")
|
level.Info(logger).Log("msg", "Configuration check successful, exiting")
|
||||||
|
@ -463,7 +492,6 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
@ -489,7 +517,7 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
level.Info(logger).Log("msg", "Received lifecycle api reload, attempting reload")
|
level.Info(logger).Log("msg", "Received lifecycle api reload, attempting reload")
|
||||||
reloadConfig(*mappingConfig, mapper, *cacheSize, logger, cacheOption)
|
reloadConfig(*mappingConfig, thisMapper, logger)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
mux.HandleFunc("/-/quit", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/-/quit", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -518,7 +546,7 @@ func main() {
|
||||||
|
|
||||||
go serveHTTP(mux, *listenAddress, logger)
|
go serveHTTP(mux, *listenAddress, logger)
|
||||||
|
|
||||||
go sighupConfigReloader(*mappingConfig, mapper, *cacheSize, logger, cacheOption)
|
go sighupConfigReloader(*mappingConfig, thisMapper, logger)
|
||||||
go exporter.Listen(events)
|
go exporter.Listen(events)
|
||||||
|
|
||||||
signals := make(chan os.Signal, 1)
|
signals := make(chan os.Signal, 1)
|
||||||
|
|
|
@ -84,5 +84,4 @@ func TestEventIntervalFlush(t *testing.T) {
|
||||||
if len(events) != 10 {
|
if len(events) != 10 {
|
||||||
t.Fatal("Expected 10 events in the event channel, but got", len(events))
|
t.Fatal("Expected 10 events in the event channel, but got", len(events))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ type Exporter struct {
|
||||||
// Listen handles all events sent to the given channel sequentially. It
|
// Listen handles all events sent to the given channel sequentially. It
|
||||||
// terminates when the channel is closed.
|
// terminates when the channel is closed.
|
||||||
func (b *Exporter) Listen(e <-chan event.Events) {
|
func (b *Exporter) Listen(e <-chan event.Events) {
|
||||||
|
|
||||||
removeStaleMetricsTicker := clock.NewTicker(time.Second)
|
removeStaleMetricsTicker := clock.NewTicker(time.Second)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -77,7 +76,6 @@ func (b *Exporter) Listen(e <-chan event.Events) {
|
||||||
|
|
||||||
// handleEvent processes a single Event according to the configured mapping.
|
// handleEvent processes a single Event according to the configured mapping.
|
||||||
func (b *Exporter) handleEvent(thisEvent event.Event) {
|
func (b *Exporter) handleEvent(thisEvent event.Event) {
|
||||||
|
|
||||||
mapping, labels, present := b.Mapper.GetMapping(thisEvent.MetricName(), thisEvent.MetricType())
|
mapping, labels, present := b.Mapper.GetMapping(thisEvent.MetricName(), thisEvent.MetricType())
|
||||||
if mapping == nil {
|
if mapping == nil {
|
||||||
mapping = &mapper.MetricMapping{}
|
mapping = &mapper.MetricMapping{}
|
||||||
|
|
|
@ -182,7 +182,6 @@ func TestNegativeCounter(t *testing.T) {
|
||||||
prev := getTelemetryCounterValue(errorCounter)
|
prev := getTelemetryCounterValue(errorCounter)
|
||||||
|
|
||||||
testMapper := mapper.MetricMapper{}
|
testMapper := mapper.MetricMapper{}
|
||||||
testMapper.InitCache(0)
|
|
||||||
|
|
||||||
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
||||||
ex.Listen(events)
|
ex.Listen(events)
|
||||||
|
@ -260,7 +259,7 @@ mappings:
|
||||||
name: "histogram_test"
|
name: "histogram_test"
|
||||||
`
|
`
|
||||||
testMapper := &mapper.MetricMapper{}
|
testMapper := &mapper.MetricMapper{}
|
||||||
err := testMapper.InitFromYAMLString(config, 0)
|
err := testMapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Config load error: %s %s", config, err)
|
t.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -318,7 +317,7 @@ mappings:
|
||||||
`
|
`
|
||||||
|
|
||||||
testMapper := &mapper.MetricMapper{}
|
testMapper := &mapper.MetricMapper{}
|
||||||
err := testMapper.InitFromYAMLString(config, 0)
|
err := testMapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Config load error: %s %s", config, err)
|
t.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -528,7 +527,7 @@ mappings:
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
t.Run(s.name, func(t *testing.T) {
|
t.Run(s.name, func(t *testing.T) {
|
||||||
testMapper := &mapper.MetricMapper{}
|
testMapper := &mapper.MetricMapper{}
|
||||||
err := testMapper.InitFromYAMLString(config, 0)
|
err := testMapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Config load error: %s %s", config, err)
|
t.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -585,7 +584,7 @@ mappings:
|
||||||
name: "${1}"
|
name: "${1}"
|
||||||
`
|
`
|
||||||
testMapper := &mapper.MetricMapper{}
|
testMapper := &mapper.MetricMapper{}
|
||||||
err := testMapper.InitFromYAMLString(config, 0)
|
err := testMapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Config load error: %s %s", config, err)
|
t.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -658,7 +657,6 @@ func TestInvalidUtf8InDatadogTagValue(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
testMapper := mapper.MetricMapper{}
|
testMapper := mapper.MetricMapper{}
|
||||||
testMapper.InitCache(0)
|
|
||||||
|
|
||||||
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
||||||
ex.Listen(events)
|
ex.Listen(events)
|
||||||
|
@ -672,7 +670,6 @@ func TestSummaryWithQuantilesEmptyMapping(t *testing.T) {
|
||||||
events := make(chan event.Events)
|
events := make(chan event.Events)
|
||||||
go func() {
|
go func() {
|
||||||
testMapper := mapper.MetricMapper{}
|
testMapper := mapper.MetricMapper{}
|
||||||
testMapper.InitCache(0)
|
|
||||||
|
|
||||||
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
||||||
ex.Listen(events)
|
ex.Listen(events)
|
||||||
|
@ -717,7 +714,6 @@ func TestHistogramUnits(t *testing.T) {
|
||||||
events := make(chan event.Events)
|
events := make(chan event.Events)
|
||||||
go func() {
|
go func() {
|
||||||
testMapper := mapper.MetricMapper{}
|
testMapper := mapper.MetricMapper{}
|
||||||
testMapper.InitCache(0)
|
|
||||||
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
||||||
ex.Mapper.Defaults.ObserverType = mapper.ObserverTypeHistogram
|
ex.Mapper.Defaults.ObserverType = mapper.ObserverTypeHistogram
|
||||||
ex.Listen(events)
|
ex.Listen(events)
|
||||||
|
@ -754,7 +750,6 @@ func TestCounterIncrement(t *testing.T) {
|
||||||
events := make(chan event.Events)
|
events := make(chan event.Events)
|
||||||
go func() {
|
go func() {
|
||||||
testMapper := mapper.MetricMapper{}
|
testMapper := mapper.MetricMapper{}
|
||||||
testMapper.InitCache(0)
|
|
||||||
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
|
||||||
ex.Listen(events)
|
ex.Listen(events)
|
||||||
}()
|
}()
|
||||||
|
@ -857,7 +852,7 @@ mappings:
|
||||||
`
|
`
|
||||||
// Create mapper from config and start an Exporter with a synchronous channel
|
// Create mapper from config and start an Exporter with a synchronous channel
|
||||||
testMapper := &mapper.MetricMapper{}
|
testMapper := &mapper.MetricMapper{}
|
||||||
err := testMapper.InitFromYAMLString(config, 0)
|
err := testMapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Config load error: %s %s", config, err)
|
t.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ var defaultQuantiles = []metricObjective{
|
||||||
{Quantile: 0.99, Error: 0.001},
|
{Quantile: 0.99, Error: 0.001},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, options ...CacheOption) error {
|
func (m *MetricMapper) InitFromYAMLString(fileContents string) error {
|
||||||
var n MetricMapper
|
var n MetricMapper
|
||||||
|
|
||||||
if err := yaml.Unmarshal([]byte(fileContents), &n); err != nil {
|
if err := yaml.Unmarshal([]byte(fileContents), &n); err != nil {
|
||||||
|
@ -144,7 +144,6 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, op
|
||||||
}
|
}
|
||||||
currentMapping.labelFormatters = labelFormatters
|
currentMapping.labelFormatters = labelFormatters
|
||||||
currentMapping.labelKeys = labelKeys
|
currentMapping.labelKeys = labelKeys
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if regex, err := regexp.Compile(currentMapping.Match); err != nil {
|
if regex, err := regexp.Compile(currentMapping.Match); err != nil {
|
||||||
return fmt.Errorf("invalid regex %s in mapping: %v", currentMapping.Match, err)
|
return fmt.Errorf("invalid regex %s in mapping: %v", currentMapping.Match, err)
|
||||||
|
@ -222,7 +221,6 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, op
|
||||||
if currentMapping.Ttl == 0 && n.Defaults.Ttl > 0 {
|
if currentMapping.Ttl == 0 && n.Defaults.Ttl > 0 {
|
||||||
currentMapping.Ttl = n.Defaults.Ttl
|
currentMapping.Ttl = n.Defaults.Ttl
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
|
@ -230,7 +228,11 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, op
|
||||||
|
|
||||||
m.Defaults = n.Defaults
|
m.Defaults = n.Defaults
|
||||||
m.Mappings = n.Mappings
|
m.Mappings = n.Mappings
|
||||||
m.InitCache(cacheSize, options...)
|
|
||||||
|
// Reset the cache since this function can be used to reload config
|
||||||
|
if m.cache != nil {
|
||||||
|
m.cache.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
if n.doFSM {
|
if n.doFSM {
|
||||||
var mappings []string
|
var mappings []string
|
||||||
|
@ -252,53 +254,36 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, op
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MetricMapper) InitFromFile(fileName string, cacheSize int, options ...CacheOption) error {
|
func (m *MetricMapper) InitFromFile(fileName string) error {
|
||||||
mappingStr, err := ioutil.ReadFile(fileName)
|
mappingStr, err := ioutil.ReadFile(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.InitFromYAMLString(string(mappingStr), cacheSize, options...)
|
return m.InitFromYAMLString(string(mappingStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MetricMapper) InitCache(cacheSize int, options ...CacheOption) {
|
// UseCache tells the mapper to use a cache that implements the MetricMapperCache interface.
|
||||||
if cacheSize == 0 {
|
// This cache MUST be thread-safe!
|
||||||
m.cache = NewMetricMapperNoopCache(m.Registerer)
|
func (m *MetricMapper) UseCache(cache MetricMapperCache) {
|
||||||
} else {
|
m.mutex.Lock()
|
||||||
o := cacheOptions{
|
defer m.mutex.Unlock()
|
||||||
cacheType: "lru",
|
|
||||||
}
|
|
||||||
for _, f := range options {
|
|
||||||
f(&o)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
cache MetricMapperCache
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
switch o.cacheType {
|
|
||||||
case "lru":
|
|
||||||
cache, err = NewMetricMapperCache(m.Registerer, cacheSize)
|
|
||||||
case "random":
|
|
||||||
cache, err = NewMetricMapperRRCache(m.Registerer, cacheSize)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("unsupported cache type %q", o.cacheType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Unable to setup metric cache. Caused by: %s", err)
|
|
||||||
}
|
|
||||||
m.cache = cache
|
m.cache = cache
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapper) GetMapping(statsdMetric string, statsdMetricType MetricType) (*MetricMapping, prometheus.Labels, bool) {
|
func (m *MetricMapper) GetMapping(statsdMetric string, statsdMetricType MetricType) (*MetricMapping, prometheus.Labels, bool) {
|
||||||
m.mutex.RLock()
|
m.mutex.RLock()
|
||||||
defer m.mutex.RUnlock()
|
defer m.mutex.RUnlock()
|
||||||
result, cached := m.cache.Get(statsdMetric, statsdMetricType)
|
|
||||||
|
// only use a cache if one is present
|
||||||
|
if m.cache != nil {
|
||||||
|
result, cached := m.cache.Get(formatKey(statsdMetric, statsdMetricType))
|
||||||
if cached {
|
if cached {
|
||||||
return result.Mapping, result.Labels, result.Matched
|
r := result.(MetricMapperCacheResult)
|
||||||
|
return r.Mapping, r.Labels, r.Matched
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// glob matching
|
// glob matching
|
||||||
if m.doFSM {
|
if m.doFSM {
|
||||||
finalState, captures := m.FSM.GetMapping(statsdMetric, string(statsdMetricType))
|
finalState, captures := m.FSM.GetMapping(statsdMetric, string(statsdMetricType))
|
||||||
|
@ -312,12 +297,23 @@ func (m *MetricMapper) GetMapping(statsdMetric string, statsdMetricType MetricTy
|
||||||
labels[result.labelKeys[index]] = formatter.Format(captures)
|
labels[result.labelKeys[index]] = formatter.Format(captures)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.cache.AddMatch(statsdMetric, statsdMetricType, result, labels)
|
r := MetricMapperCacheResult{
|
||||||
|
Mapping: result,
|
||||||
|
Matched: true,
|
||||||
|
Labels: labels,
|
||||||
|
}
|
||||||
|
// add match to cache
|
||||||
|
if m.cache != nil {
|
||||||
|
m.cache.Add(formatKey(statsdMetric, statsdMetricType), r)
|
||||||
|
}
|
||||||
|
|
||||||
return result, labels, true
|
return result, labels, true
|
||||||
} else if !m.doRegex {
|
} else if !m.doRegex {
|
||||||
// if there's no regex match type, return immediately
|
// if there's no regex match type, return immediately
|
||||||
m.cache.AddMiss(statsdMetric, statsdMetricType)
|
// Add miss to cache
|
||||||
|
if m.cache != nil {
|
||||||
|
m.cache.Add(formatKey(statsdMetric, statsdMetricType), MetricMapperCacheResult{})
|
||||||
|
}
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,12 +346,23 @@ func (m *MetricMapper) GetMapping(statsdMetric string, statsdMetricType MetricTy
|
||||||
labels[label] = string(value)
|
labels[label] = string(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.cache.AddMatch(statsdMetric, statsdMetricType, &mapping, labels)
|
r := MetricMapperCacheResult{
|
||||||
|
Mapping: &mapping,
|
||||||
|
Matched: true,
|
||||||
|
Labels: labels,
|
||||||
|
}
|
||||||
|
// Add Match to cache
|
||||||
|
if m.cache != nil {
|
||||||
|
m.cache.Add(formatKey(statsdMetric, statsdMetricType), r)
|
||||||
|
}
|
||||||
|
|
||||||
return &mapping, labels, true
|
return &mapping, labels, true
|
||||||
}
|
}
|
||||||
|
|
||||||
m.cache.AddMiss(statsdMetric, statsdMetricType)
|
// Add Miss to cache
|
||||||
|
if m.cache != nil {
|
||||||
|
m.cache.Add(formatKey(statsdMetric, statsdMetricType), MetricMapperCacheResult{})
|
||||||
|
}
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache/lru"
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache/randomreplacement"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -105,7 +108,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -169,7 +172,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -240,7 +243,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -304,7 +307,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -331,7 +334,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -359,7 +362,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -385,7 +388,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -412,7 +415,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -438,7 +441,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -465,7 +468,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -502,7 +505,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -540,7 +543,7 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -561,7 +564,7 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -582,9 +585,10 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := newTestMapperWithCache(cacheType, 1000)
|
||||||
|
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
err := mapper.InitFromYAMLString(config)
|
||||||
err := mapper.InitFromYAMLString(config, 1000, WithCacheType(cacheType))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -609,7 +613,7 @@ mappings:` + duplicateRules(10, ruleTemplateSingleMatchRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -632,9 +636,19 @@ mappings:` + duplicateRules(10, ruleTemplateSingleMatchRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
var cache MetricMapperCache
|
||||||
|
switch cacheType {
|
||||||
|
case "lru":
|
||||||
|
cache, _ = lru.NewMetricMapperLRUCache(mapper.Registerer, 1000)
|
||||||
|
case "random":
|
||||||
|
cache, _ = randomreplacement.NewMetricMapperRRCache(mapper.Registerer, 1000)
|
||||||
|
}
|
||||||
|
mapper.UseCache(cache)
|
||||||
|
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 1000, WithCacheType(cacheType))
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -657,7 +671,7 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -678,9 +692,10 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := newTestMapperWithCache(cacheType, 1000)
|
||||||
|
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
err := mapper.InitFromYAMLString(config)
|
||||||
err := mapper.InitFromYAMLString(config, 1000, WithCacheType(cacheType))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -703,7 +718,7 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -726,7 +741,7 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -749,7 +764,7 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -772,7 +787,7 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -793,7 +808,7 @@ mappings:` + duplicateRules(100, ruleTemplateMultipleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -814,9 +829,10 @@ mappings:` + duplicateRules(100, ruleTemplateMultipleMatchGlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := newTestMapperWithCache(cacheType, 1000)
|
||||||
|
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
err := mapper.InitFromYAMLString(config)
|
||||||
err := mapper.InitFromYAMLString(config, 1000, WithCacheType(cacheType))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -841,7 +857,7 @@ mappings:` + duplicateRules(100, ruleTemplateMultipleMatchRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -864,7 +880,7 @@ mappings:` + duplicateRules(100, ruleTemplateMultipleMatchRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -887,9 +903,10 @@ mappings:` + duplicateRules(100, ruleTemplateMultipleMatchRegex)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := newTestMapperWithCache(cacheType, 1000)
|
||||||
|
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
err := mapper.InitFromYAMLString(config)
|
||||||
err := mapper.InitFromYAMLString(config, 1000, WithCacheType(cacheType))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -914,14 +931,15 @@ func duplicateMetrics(count int, template string) []string {
|
||||||
|
|
||||||
func BenchmarkGlob100RulesCached100Metrics(b *testing.B) {
|
func BenchmarkGlob100RulesCached100Metrics(b *testing.B) {
|
||||||
config := `---
|
config := `---
|
||||||
mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
mappings:` + duplicateRules(101, ruleTemplateSingleMatchGlob)
|
||||||
|
|
||||||
mappings := duplicateMetrics(100, "metric100")
|
mappings := duplicateMetrics(100, "metric100")
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := newTestMapperWithCache(cacheType, 1000)
|
||||||
|
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
err := mapper.InitFromYAMLString(config)
|
||||||
err := mapper.InitFromYAMLString(config, 1000, WithCacheType(cacheType))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -947,9 +965,10 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
mappings := duplicateMetrics(100, "metric100")
|
mappings := duplicateMetrics(100, "metric100")
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := newTestMapperWithCache(cacheType, 1000)
|
||||||
|
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
err := mapper.InitFromYAMLString(config)
|
||||||
err := mapper.InitFromYAMLString(config, 50, WithCacheType(cacheType))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
@ -982,9 +1001,9 @@ mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, cacheType := range []string{"lru", "random"} {
|
for _, cacheType := range []string{"lru", "random"} {
|
||||||
|
mapper := newTestMapperWithCache(cacheType, 50)
|
||||||
b.Run(cacheType, func(b *testing.B) {
|
b.Run(cacheType, func(b *testing.B) {
|
||||||
mapper := MetricMapper{}
|
err := mapper.InitFromYAMLString(config)
|
||||||
err := mapper.InitFromYAMLString(config, 50, WithCacheType(cacheType))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Config load error: %s %s", config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,6 @@
|
||||||
package mapper
|
package mapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -56,155 +53,22 @@ func NewCacheMetrics(reg prometheus.Registerer) *CacheMetrics {
|
||||||
return &m
|
return &m
|
||||||
}
|
}
|
||||||
|
|
||||||
type cacheOptions struct {
|
|
||||||
cacheType string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CacheOption func(*cacheOptions)
|
|
||||||
|
|
||||||
func WithCacheType(cacheType string) CacheOption {
|
|
||||||
return func(o *cacheOptions) {
|
|
||||||
o.cacheType = cacheType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type MetricMapperCacheResult struct {
|
type MetricMapperCacheResult struct {
|
||||||
Mapping *MetricMapping
|
Mapping *MetricMapping
|
||||||
Matched bool
|
Matched bool
|
||||||
Labels prometheus.Labels
|
Labels prometheus.Labels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MetricMapperCache MUST be thread-safe and should be instrumented with CacheMetrics
|
||||||
type MetricMapperCache interface {
|
type MetricMapperCache interface {
|
||||||
Get(metricString string, metricType MetricType) (*MetricMapperCacheResult, bool)
|
// Get a cached result
|
||||||
AddMatch(metricString string, metricType MetricType, mapping *MetricMapping, labels prometheus.Labels)
|
Get(metricKey string) (interface{}, bool)
|
||||||
AddMiss(metricString string, metricType MetricType)
|
// Add a statsd MetricMapperResult to the cache
|
||||||
}
|
Add(metricKey string, result interface{}) // Add an item to the cache
|
||||||
|
// Reset clears the cache for config reloads
|
||||||
type MetricMapperLRUCache struct {
|
Reset()
|
||||||
MetricMapperCache
|
|
||||||
cache *lru.Cache
|
|
||||||
metrics *CacheMetrics
|
|
||||||
}
|
|
||||||
|
|
||||||
type MetricMapperNoopCache struct {
|
|
||||||
MetricMapperCache
|
|
||||||
metrics *CacheMetrics
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMetricMapperCache(reg prometheus.Registerer, size int) (*MetricMapperLRUCache, error) {
|
|
||||||
metrics := NewCacheMetrics(reg)
|
|
||||||
cache, err := lru.New(size)
|
|
||||||
if err != nil {
|
|
||||||
return &MetricMapperLRUCache{}, err
|
|
||||||
}
|
|
||||||
return &MetricMapperLRUCache{metrics: metrics, cache: cache}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperLRUCache) Get(metricString string, metricType MetricType) (*MetricMapperCacheResult, bool) {
|
|
||||||
m.metrics.CacheGetsTotal.Inc()
|
|
||||||
if result, ok := m.cache.Get(formatKey(metricString, metricType)); ok {
|
|
||||||
m.metrics.CacheHitsTotal.Inc()
|
|
||||||
return result.(*MetricMapperCacheResult), true
|
|
||||||
} else {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperLRUCache) AddMatch(metricString string, metricType MetricType, mapping *MetricMapping, labels prometheus.Labels) {
|
|
||||||
go m.trackCacheLength()
|
|
||||||
m.cache.Add(formatKey(metricString, metricType), &MetricMapperCacheResult{Mapping: mapping, Matched: true, Labels: labels})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperLRUCache) AddMiss(metricString string, metricType MetricType) {
|
|
||||||
go m.trackCacheLength()
|
|
||||||
m.cache.Add(formatKey(metricString, metricType), &MetricMapperCacheResult{Matched: false})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperLRUCache) trackCacheLength() {
|
|
||||||
m.metrics.CacheLength.Set(float64(m.cache.Len()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatKey(metricString string, metricType MetricType) string {
|
func formatKey(metricString string, metricType MetricType) string {
|
||||||
return string(metricType) + "." + metricString
|
return string(metricType) + "." + metricString
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMetricMapperNoopCache(reg prometheus.Registerer) *MetricMapperNoopCache {
|
|
||||||
return &MetricMapperNoopCache{metrics: NewCacheMetrics(reg)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperNoopCache) Get(metricString string, metricType MetricType) (*MetricMapperCacheResult, bool) {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperNoopCache) AddMatch(metricString string, metricType MetricType, mapping *MetricMapping, labels prometheus.Labels) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperNoopCache) AddMiss(metricString string, metricType MetricType) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type MetricMapperRRCache struct {
|
|
||||||
MetricMapperCache
|
|
||||||
lock sync.RWMutex
|
|
||||||
size int
|
|
||||||
items map[string]*MetricMapperCacheResult
|
|
||||||
metrics *CacheMetrics
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMetricMapperRRCache(reg prometheus.Registerer, size int) (*MetricMapperRRCache, error) {
|
|
||||||
metrics := NewCacheMetrics(reg)
|
|
||||||
c := &MetricMapperRRCache{
|
|
||||||
items: make(map[string]*MetricMapperCacheResult, size+1),
|
|
||||||
size: size,
|
|
||||||
metrics: metrics,
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperRRCache) Get(metricString string, metricType MetricType) (*MetricMapperCacheResult, bool) {
|
|
||||||
key := formatKey(metricString, metricType)
|
|
||||||
|
|
||||||
m.lock.RLock()
|
|
||||||
result, ok := m.items[key]
|
|
||||||
m.lock.RUnlock()
|
|
||||||
|
|
||||||
return result, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperRRCache) addItem(metricString string, metricType MetricType, result *MetricMapperCacheResult) {
|
|
||||||
go m.trackCacheLength()
|
|
||||||
|
|
||||||
key := formatKey(metricString, metricType)
|
|
||||||
|
|
||||||
m.lock.Lock()
|
|
||||||
|
|
||||||
m.items[key] = result
|
|
||||||
|
|
||||||
// evict an item if needed
|
|
||||||
if len(m.items) > m.size {
|
|
||||||
for k := range m.items {
|
|
||||||
delete(m.items, k)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperRRCache) AddMatch(metricString string, metricType MetricType, mapping *MetricMapping, labels prometheus.Labels) {
|
|
||||||
e := &MetricMapperCacheResult{Mapping: mapping, Matched: true, Labels: labels}
|
|
||||||
m.addItem(metricString, metricType, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperRRCache) AddMiss(metricString string, metricType MetricType) {
|
|
||||||
e := &MetricMapperCacheResult{Matched: false}
|
|
||||||
m.addItem(metricString, metricType, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapperRRCache) trackCacheLength() {
|
|
||||||
m.lock.RLock()
|
|
||||||
length := len(m.items)
|
|
||||||
m.lock.RUnlock()
|
|
||||||
m.metrics.CacheLength.Set(float64(length))
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,6 +18,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache/lru"
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache/randomreplacement"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mappings []struct {
|
type mappings []struct {
|
||||||
|
@ -34,6 +37,21 @@ type mappings []struct {
|
||||||
buckets []float64
|
buckets []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newTestMapperWithCache(cacheType string, size int) *MetricMapper {
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
var cache MetricMapperCache
|
||||||
|
switch cacheType {
|
||||||
|
case "lru":
|
||||||
|
cache, _ = lru.NewMetricMapperLRUCache(mapper.Registerer, size)
|
||||||
|
case "random":
|
||||||
|
cache, _ = randomreplacement.NewMetricMapperRRCache(mapper.Registerer, size)
|
||||||
|
case "none":
|
||||||
|
return &mapper
|
||||||
|
}
|
||||||
|
mapper.UseCache(cache)
|
||||||
|
return &mapper
|
||||||
|
}
|
||||||
|
|
||||||
func TestMetricMapperYAML(t *testing.T) {
|
func TestMetricMapperYAML(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
testName string
|
testName string
|
||||||
|
@ -1379,12 +1397,15 @@ mappings:
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
|
cache, _ := lru.NewMetricMapperLRUCache(mapper.Registerer, 1000)
|
||||||
|
mapper.UseCache(cache)
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
for i, scenario := range scenarios {
|
||||||
if scenario.testName == "" {
|
if scenario.testName == "" {
|
||||||
t.Fatalf("Missing testName in scenario %+v", scenario)
|
t.Fatalf("Missing testName in scenario %+v", scenario)
|
||||||
}
|
}
|
||||||
t.Run(scenario.testName, func(t *testing.T) {
|
t.Run(scenario.testName, func(t *testing.T) {
|
||||||
err := mapper.InitFromYAMLString(scenario.config, 1000)
|
err := mapper.InitFromYAMLString(scenario.config)
|
||||||
if err != nil && !scenario.configBad {
|
if err != nil && !scenario.configBad {
|
||||||
t.Fatalf("%d. Config load error: %s %s", i, scenario.config, err)
|
t.Fatalf("%d. Config load error: %s %s", i, scenario.config, err)
|
||||||
}
|
}
|
||||||
|
@ -1542,7 +1563,7 @@ mappings:
|
||||||
}
|
}
|
||||||
t.Run(scenario.testName, func(t *testing.T) {
|
t.Run(scenario.testName, func(t *testing.T) {
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(scenario.config, 0)
|
err := mapper.InitFromYAMLString(scenario.config)
|
||||||
if err != nil && !scenario.configBad {
|
if err != nil && !scenario.configBad {
|
||||||
t.Fatalf("%d. Config load error: %s %s", i, scenario.config, err)
|
t.Fatalf("%d. Config load error: %s %s", i, scenario.config, err)
|
||||||
}
|
}
|
||||||
|
@ -1570,11 +1591,6 @@ mappings:
|
||||||
labels:
|
labels:
|
||||||
app: "$2"
|
app: "$2"
|
||||||
`
|
`
|
||||||
mapper := MetricMapper{}
|
|
||||||
err := mapper.InitFromYAMLString(config, 0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("config load error: %s ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
names := map[string]string{
|
names := map[string]string{
|
||||||
"aa.bb.aa.myapp": "aa_bb_aa_total",
|
"aa.bb.aa.myapp": "aa_bb_aa_total",
|
||||||
|
@ -1583,19 +1599,14 @@ mappings:
|
||||||
"aa.bb.dd.myapp": "aa_bb_dd_total",
|
"aa.bb.dd.myapp": "aa_bb_dd_total",
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []struct {
|
scenarios := []string{"none", "lru"}
|
||||||
cacheSize int
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
cacheSize: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cacheSize: len(names),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
for i, scenario := range scenarios {
|
||||||
mapper.InitCache(scenario.cacheSize)
|
mapper := newTestMapperWithCache(scenario, 1000)
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("config load error: %s ", err)
|
||||||
|
}
|
||||||
|
|
||||||
// run multiple times to ensure cache works as expected
|
// run multiple times to ensure cache works as expected
|
||||||
for j := 0; j < 10; j++ {
|
for j := 0; j < 10; j++ {
|
||||||
|
@ -1610,5 +1621,4 @@ mappings:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
65
pkg/mappercache/lru/lru.go
Normal file
65
pkg/mappercache/lru/lru.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright 2021 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package lru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
lru2 "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache"
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricMapperLRUCache struct {
|
||||||
|
cache *lru2.Cache
|
||||||
|
metrics *mappercache.CacheMetrics
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMetricMapperLRUCache(reg prometheus.Registerer, size int) (*metricMapperLRUCache, error) {
|
||||||
|
if size <= 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics := mappercache.NewCacheMetrics(reg)
|
||||||
|
cache, err := lru2.New(size)
|
||||||
|
if err != nil {
|
||||||
|
return &metricMapperLRUCache{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &metricMapperLRUCache{metrics: metrics, cache: cache}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperLRUCache) Get(metricKey string) (interface{}, bool) {
|
||||||
|
m.metrics.CacheGetsTotal.Inc()
|
||||||
|
if result, ok := m.cache.Get(metricKey); ok {
|
||||||
|
m.metrics.CacheHitsTotal.Inc()
|
||||||
|
return result, true
|
||||||
|
} else {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperLRUCache) Add(metricKey string, result interface{}) {
|
||||||
|
go m.trackCacheLength()
|
||||||
|
m.cache.Add(metricKey, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperLRUCache) trackCacheLength() {
|
||||||
|
m.metrics.CacheLength.Set(float64(m.cache.Len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperLRUCache) Reset() {
|
||||||
|
m.cache.Purge()
|
||||||
|
m.metrics.CacheLength.Set(0)
|
||||||
|
}
|
52
pkg/mappercache/metrics.go
Normal file
52
pkg/mappercache/metrics.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright 2021 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package mappercache
|
||||||
|
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
type CacheMetrics struct {
|
||||||
|
CacheLength prometheus.Gauge
|
||||||
|
CacheGetsTotal prometheus.Counter
|
||||||
|
CacheHitsTotal prometheus.Counter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCacheMetrics(reg prometheus.Registerer) *CacheMetrics {
|
||||||
|
var m CacheMetrics
|
||||||
|
|
||||||
|
m.CacheLength = prometheus.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "statsd_metric_mapper_cache_length",
|
||||||
|
Help: "The count of unique metrics currently cached.",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
m.CacheGetsTotal = prometheus.NewCounter(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "statsd_metric_mapper_cache_gets_total",
|
||||||
|
Help: "The count of total metric cache gets.",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
m.CacheHitsTotal = prometheus.NewCounter(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "statsd_metric_mapper_cache_hits_total",
|
||||||
|
Help: "The count of total metric cache hits.",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if reg != nil {
|
||||||
|
reg.MustRegister(m.CacheLength)
|
||||||
|
reg.MustRegister(m.CacheGetsTotal)
|
||||||
|
reg.MustRegister(m.CacheHitsTotal)
|
||||||
|
}
|
||||||
|
return &m
|
||||||
|
}
|
83
pkg/mappercache/randomreplacement/randomreplacement.go
Normal file
83
pkg/mappercache/randomreplacement/randomreplacement.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright 2021 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package randomreplacement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
"github.com/prometheus/statsd_exporter/pkg/mappercache"
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricMapperRRCache struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
size int
|
||||||
|
items map[string]interface{}
|
||||||
|
metrics *mappercache.CacheMetrics
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMetricMapperRRCache(reg prometheus.Registerer, size int) (*metricMapperRRCache, error) {
|
||||||
|
if size <= 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics := mappercache.NewCacheMetrics(reg)
|
||||||
|
c := &metricMapperRRCache{
|
||||||
|
items: make(map[string]interface{}, size+1),
|
||||||
|
size: size,
|
||||||
|
metrics: metrics,
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperRRCache) Get(metricKey string) (interface{}, bool) {
|
||||||
|
m.lock.RLock()
|
||||||
|
result, ok := m.items[metricKey]
|
||||||
|
m.lock.RUnlock()
|
||||||
|
|
||||||
|
return result, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperRRCache) Add(metricKey string, result interface{}) {
|
||||||
|
go m.trackCacheLength()
|
||||||
|
|
||||||
|
m.lock.Lock()
|
||||||
|
|
||||||
|
m.items[metricKey] = result
|
||||||
|
|
||||||
|
// evict an item if needed
|
||||||
|
if len(m.items) > m.size {
|
||||||
|
for k := range m.items {
|
||||||
|
delete(m.items, k)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperRRCache) Reset() {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
m.items = make(map[string]interface{}, m.size+1)
|
||||||
|
m.metrics.CacheLength.Set(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricMapperRRCache) trackCacheLength() {
|
||||||
|
m.lock.RLock()
|
||||||
|
length := len(m.items)
|
||||||
|
m.lock.RUnlock()
|
||||||
|
m.metrics.CacheLength.Set(float64(length))
|
||||||
|
}
|
Loading…
Reference in a new issue