github.com/Psiphon-Labs/goarista@v0.0.0-20160825065156-d002785f4c67/cmd/octsdb/config.go (about)

     1  // Copyright (C) 2016  Arista Networks, Inc.
     2  // Use of this source code is governed by the Apache License 2.0
     3  // that can be found in the COPYING file.
     4  
     5  package main
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"regexp"
    12  	"strings"
    13  )
    14  
    15  // Config is the representation of octsdb's JSON config file.
    16  type Config struct {
    17  	// Prefixes to subscribe to.
    18  	Subscriptions []string
    19  
    20  	// MetricPrefix, if set, is used to prefix all the metric names.
    21  	MetricPrefix string
    22  
    23  	// Metrics to collect and how to munge them.
    24  	Metrics map[string]*Metric
    25  }
    26  
    27  // A Metric to collect and how to massage it into an OpenTSDB put.
    28  type Metric struct {
    29  	// Path is a regexp to match on the Update's full path.
    30  	// The regexp must be a prefix match.
    31  	// The regexp can define named capture groups to use as tags.
    32  	Path string
    33  
    34  	// Path compiled as a regexp.
    35  	re *regexp.Regexp
    36  
    37  	// Additional tags to add to this metric.
    38  	Tags map[string]string
    39  }
    40  
    41  func loadConfig(path string) (*Config, error) {
    42  	cfg, err := ioutil.ReadFile(path)
    43  	if err != nil {
    44  		return nil, fmt.Errorf("Failed to load config: %v", err)
    45  	}
    46  	config := new(Config)
    47  	err = json.Unmarshal(cfg, config)
    48  	if err != nil {
    49  		return nil, fmt.Errorf("Failed to parse config: %v", err)
    50  	}
    51  	for _, metric := range config.Metrics {
    52  		metric.re = regexp.MustCompile(metric.Path)
    53  	}
    54  	return config, nil
    55  }
    56  
    57  // Match applies this config to the given OpenConfig path.
    58  // If the path doesn't match anything in the config, an empty string
    59  // is returned as the metric name.
    60  func (c *Config) Match(path string) (metricName string, tags map[string]string) {
    61  	tags = make(map[string]string)
    62  
    63  	for _, metric := range c.Metrics {
    64  		found := metric.re.FindStringSubmatch(path)
    65  		if found == nil {
    66  			continue
    67  		}
    68  		for i, name := range metric.re.SubexpNames() {
    69  			if i == 0 {
    70  				continue
    71  			} else if name == "" {
    72  				if metricName != "" {
    73  					metricName += "/"
    74  				}
    75  				metricName += found[i]
    76  			} else {
    77  				tags[name] = found[i]
    78  			}
    79  		}
    80  		for tag, value := range metric.Tags {
    81  			tags[tag] = value
    82  		}
    83  		break
    84  	}
    85  	if metricName != "" {
    86  		metricName = strings.ToLower(strings.Replace(metricName, "/", ".", -1))
    87  		if c.MetricPrefix != "" {
    88  			metricName = c.MetricPrefix + "." + metricName
    89  		}
    90  	}
    91  	return
    92  }