diff --git a/CHANGELOG.md b/CHANGELOG.md index 023b88e..8b9aac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v3.3.3 + +* add: custom metric support + # v3.3.2 * fix: put locking in snapshot handlers diff --git a/circonus-gometrics.go b/circonus-gometrics.go index 125a79c..0d2cfdc 100644 --- a/circonus-gometrics.go +++ b/circonus-gometrics.go @@ -30,10 +30,13 @@ package circonusgometrics import ( + "fmt" "io/ioutil" "log" "os" + "regexp" "strconv" + "strings" "sync" "time" @@ -43,6 +46,43 @@ import ( const ( defaultFlushInterval = "10s" // 10 * time.Second + + // MetricTypeInt32 reconnoiter + MetricTypeInt32 = "i" + + // MetricTypeUint32 reconnoiter + MetricTypeUint32 = "I" + + // MetricTypeInt64 reconnoiter + MetricTypeInt64 = "l" + + // MetricTypeUint64 reconnoiter + MetricTypeUint64 = "L" + + // MetricTypeFloat64 reconnoiter + MetricTypeFloat64 = "n" + + // MetricTypeString reconnoiter + MetricTypeString = "s" + + // MetricTypeHistogram reconnoiter + MetricTypeHistogram = "h" + + // MetricTypeCumulativeHistogram reconnoiter + MetricTypeCumulativeHistogram = "H" +) + +var ( + metricTypeRx = regexp.MustCompile(`^[` + strings.Join([]string{ + MetricTypeInt32, + MetricTypeUint32, + MetricTypeInt64, + MetricTypeUint64, + MetricTypeFloat64, + MetricTypeString, + MetricTypeHistogram, + MetricTypeCumulativeHistogram, + }, "") + `]$`) ) // Logger facilitates use of any logger supporting the required methods @@ -120,6 +160,9 @@ type CirconusMetrics struct { textFuncs map[string]func() string tfm sync.Mutex + + custom map[string]Metric + custm sync.Mutex } // NewCirconusMetrics returns a CirconusMetrics instance @@ -142,6 +185,7 @@ func New(cfg *Config) (*CirconusMetrics, error) { histograms: make(map[string]*Histogram), text: make(map[string]string), textFuncs: make(map[string]func() string), + custom: make(map[string]Metric), lastMetrics: &prevMetrics{}, } @@ -247,3 +291,16 @@ func (m *CirconusMetrics) Start() { func (m *CirconusMetrics) Ready() bool { return m.check.IsReady() } + +// Custom adds a user defined metric +func (m *CirconusMetrics) Custom(metricName string, metric Metric) error { + if !metricTypeRx.MatchString(metric.Type) { + return fmt.Errorf("unrecognized circonus metric type (%s)", metric.Type) + } + + m.custm.Lock() + m.custom[metricName] = metric + m.custm.Unlock() + + return nil +} diff --git a/metric_output.go b/metric_output.go index d73c440..48e8e59 100644 --- a/metric_output.go +++ b/metric_output.go @@ -28,9 +28,18 @@ func (m *CirconusMetrics) packageMetrics() (map[string]*apiclient.CheckBundleMet ts := makeTimestamp(time.Now()) - counters, gauges, histograms, text := m.snapshot() newMetrics := make(map[string]*apiclient.CheckBundleMetric) - output := make(Metrics, len(counters)+len(gauges)+len(histograms)+len(text)) + counters, gauges, histograms, text := m.snapshot() + m.custm.Lock() + output := make(Metrics, len(counters)+len(gauges)+len(histograms)+len(text)+len(m.custom)) + if len(m.custom) > 0 { + // add and reset any custom metrics + for mn, mv := range m.custom { + output[mn] = mv + } + m.custom = make(map[string]Metric) + } + m.custm.Unlock() for name, value := range counters { send := m.check.IsMetricActive(name) if !send && m.check.ActivateMetric(name) {