ipld-eth-server/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config.go
Matt K 293dd2e848 Add vendor dir (#16) (#4)
* Add vendor dir so builds dont require dep

* Pin specific version go-eth version
2018-01-29 13:44:18 -06:00

120 lines
3.1 KiB
Go

// Copyright (c) 2017 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
package main
import (
"fmt"
"regexp"
"strconv"
"github.com/prometheus/client_golang/prometheus"
"gopkg.in/yaml.v2"
)
// Config is the representation of ocprometheus's YAML config file.
type Config struct {
// Per-device labels.
DeviceLabels map[string]prometheus.Labels
// Prefixes to subscribe to.
Subscriptions []string
// Metrics to collect and how to munge them.
Metrics []*MetricDef
}
// MetricDef is the representation of a metric definiton in the config file.
type MetricDef struct {
// Path is a regexp to match on the Update's full path.
// The regexp must be a prefix match.
// The regexp can define named capture groups to use as labels.
Path string
// Path compiled as a regexp.
re *regexp.Regexp
// Metric name.
Name string
// Metric help string.
Help string
// This map contains the metric descriptors for this metric for each device.
devDesc map[string]*prometheus.Desc
// This is the default metric descriptor for devices that don't have explicit descs.
desc *prometheus.Desc
}
// Parses the config and creates the descriptors for each path and device.
func parseConfig(cfg []byte) (*Config, error) {
config := &Config{
DeviceLabels: make(map[string]prometheus.Labels),
}
if err := yaml.Unmarshal(cfg, config); err != nil {
return nil, fmt.Errorf("Failed to parse config: %v", err)
}
for _, def := range config.Metrics {
def.re = regexp.MustCompile(def.Path)
// Extract label names
reNames := def.re.SubexpNames()[1:]
labelNames := make([]string, len(reNames))
for i, n := range reNames {
labelNames[i] = n
if n == "" {
labelNames[i] = "unnamedLabel" + strconv.Itoa(i+1)
}
}
// Create a default descriptor only if there aren't any per-device labels,
// or if it's explicitly declared
if len(config.DeviceLabels) == 0 || len(config.DeviceLabels["*"]) > 0 {
def.desc = prometheus.NewDesc(def.Name, def.Help, labelNames, config.DeviceLabels["*"])
}
// Add per-device descriptors
def.devDesc = make(map[string]*prometheus.Desc)
for device, labels := range config.DeviceLabels {
if device == "*" {
continue
}
def.devDesc[device] = prometheus.NewDesc(def.Name, def.Help, labelNames, labels)
}
}
return config, nil
}
// Returns the descriptor corresponding to the device and path, and labels extracted from the path.
// If the device and path doesn't match any metrics, returns nil.
func (c *Config) getDescAndLabels(s source) (*prometheus.Desc, []string) {
for _, def := range c.Metrics {
if groups := def.re.FindStringSubmatch(s.path); groups != nil {
if desc, ok := def.devDesc[s.addr]; ok {
return desc, groups[1:]
}
return def.desc, groups[1:]
}
}
return nil, nil
}
// Sends all the descriptors to the channel.
func (c *Config) getAllDescs(ch chan<- *prometheus.Desc) {
for _, def := range c.Metrics {
// Default descriptor might not be present
if def.desc != nil {
ch <- def.desc
}
for _, desc := range def.devDesc {
ch <- desc
}
}
}