config/metrics.go (93 lines of code) (raw):

// Copyright 2017 Google Inc. // // 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 // // https://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 config import ( "errors" "fmt" "reflect" "github.com/GoogleCloudPlatform/ubbagent/metrics" ) type metricValidator interface { Validate(m *Metric, c *Config) error } type Metric struct { metrics.Definition `json:",inline"` Endpoints []MetricEndpoint `json:"endpoints"` // oneof - buffering configuration Aggregation *Aggregation `json:"aggregation"` Passthrough *Passthrough `json:"passthrough"` } func (m *Metric) Validate(c *Config) error { if err := m.Definition.Validate(); err != nil { return err } types := 0 for _, v := range []metricValidator{m.Aggregation, m.Passthrough} { if reflect.ValueOf(v).IsNil() { continue } if err := v.Validate(m, c); err != nil { return fmt.Errorf("metric %v: %v", m.Name, err) } types++ } if types == 0 { return fmt.Errorf("metric %v: missing buffering configuration", m.Name) } if types > 1 { return fmt.Errorf("metric %v: multiple buffering configurations", m.Name) } if len(m.Endpoints) == 0 { return fmt.Errorf("metric %v: no endpoints defined", m.Name) } usedEndpoints := make(map[string]bool) for _, e := range m.Endpoints { if e.Name == "" { return fmt.Errorf("metric %v: endpoint missing name", m.Name) } if !c.Endpoints.exists(e.Name) { return fmt.Errorf("metric %v: endpoint does not exist: %v", m.Name, e.Name) } if usedEndpoints[e.Name] { return fmt.Errorf("metric %v: endpoint listed twice: %v", m.Name, e.Name) } usedEndpoints[e.Name] = true } return nil } type Metrics []Metric // GetMetricDefinition returns the metrics.Definition with the given name, or nil if it does not // exist. func (m Metrics) GetMetricDefinition(name string) *metrics.Definition { for i := range m { if m[i].Name == name { return &m[i].Definition } } return nil } // Validate checks validity of metric configuration. Specifically, it must not contain duplicate // metric definitions, and metric definitions must specify valid type names. func (m Metrics) Validate(c *Config) error { usedNames := make(map[string]bool) for _, def := range m { if err := def.Validate(c); err != nil { return err } if usedNames[def.Name] { return errors.New(fmt.Sprintf("metric %v: duplicate name: %v", def.Name, def.Name)) } usedNames[def.Name] = true } return nil } type MetricEndpoint struct { Name string `json:"name"` } type Aggregation struct { // The number of seconds that metrics should be aggregated prior to forwarding BufferSeconds int64 `json:"bufferSeconds"` } func (rm *Aggregation) Validate(m *Metric, c *Config) error { if rm.BufferSeconds <= 0 { return fmt.Errorf("bufferSeconds must be > 0") } return nil } type Passthrough struct { } func (rm *Passthrough) Validate(m *Metric, c *Config) error { return nil }