diff --git a/command/agent/command.go b/command/agent/command.go index 9b1348c94..589576ee4 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -656,6 +656,8 @@ func (c *Command) setupTelemetry(config *Config) error { cfg.CheckManager.Check.ForceMetricActivation = telConfig.CirconusCheckForceMetricActivation cfg.CheckManager.Check.InstanceID = telConfig.CirconusCheckInstanceID cfg.CheckManager.Check.SearchTag = telConfig.CirconusCheckSearchTag + cfg.CheckManager.Check.Tags = telConfig.CirconusCheckTags + cfg.CheckManager.Check.DisplayName = telConfig.CirconusCheckDisplayName cfg.CheckManager.Broker.ID = telConfig.CirconusBrokerID cfg.CheckManager.Broker.SelectTag = telConfig.CirconusBrokerSelectTag @@ -663,12 +665,6 @@ func (c *Command) setupTelemetry(config *Config) error { cfg.CheckManager.API.TokenApp = "nomad" } - if cfg.CheckManager.Check.InstanceID == "" { - if config.NodeName != "" && config.Datacenter != "" { - cfg.CheckManager.Check.InstanceID = fmt.Sprintf("%s:%s", config.NodeName, config.Datacenter) - } - } - if cfg.CheckManager.Check.SearchTag == "" { cfg.CheckManager.Check.SearchTag = "service:nomad" } diff --git a/command/agent/config.go b/command/agent/config.go index b98784690..bf3ea22a7 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -319,6 +319,13 @@ type Telemetry struct { // narrow down the search results when neither a Submission URL or Check ID is provided. // Default: service:app (e.g. service:nomad) CirconusCheckSearchTag string `mapstructure:"circonus_check_search_tag"` + // CirconusCheckTags is a comma separated list of tags to apply to the check. Note that + // the value of CirconusCheckSearchTag will always be added to the check. + // Default: none + CirconusCheckTags string `mapstructure:"circonus_check_tags"` + // CirconusCheckDisplayName is the name for the check which will be displayed in the Circonus UI. + // Default: value of CirconusCheckInstanceID + CirconusCheckDisplayName string `mapstructure:"circonus_check_display_name"` // CirconusBrokerID is an explicit broker to use when creating a new check. The numeric portion // of broker._cid. If metric management is enabled and neither a Submission URL nor Check ID // is provided, an attempt will be made to search for an existing check using Instance ID and @@ -832,6 +839,12 @@ func (a *Telemetry) Merge(b *Telemetry) *Telemetry { if b.CirconusCheckSearchTag != "" { result.CirconusCheckSearchTag = b.CirconusCheckSearchTag } + if b.CirconusCheckTags != "" { + result.CirconusCheckTags = b.CirconusCheckTags + } + if b.CirconusCheckDisplayName != "" { + result.CirconusCheckDisplayName = b.CirconusCheckDisplayName + } if b.CirconusBrokerID != "" { result.CirconusBrokerID = b.CirconusBrokerID } diff --git a/command/agent/config_parse.go b/command/agent/config_parse.go index 701c9bfa0..0993abf8f 100644 --- a/command/agent/config_parse.go +++ b/command/agent/config_parse.go @@ -540,6 +540,8 @@ func parseTelemetry(result **Telemetry, list *ast.ObjectList) error { "circonus_check_force_metric_activation", "circonus_check_instance_id", "circonus_check_search_tag", + "circonus_check_display_name", + "circonus_check_tags", "circonus_broker_id", "circonus_broker_select_tag", } diff --git a/command/agent/config_test.go b/command/agent/config_test.go index 40c9eca27..453d7250c 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -47,6 +47,8 @@ func TestConfig_Merge(t *testing.T) { CirconusCheckForceMetricActivation: "true", CirconusCheckInstanceID: "node1:nomadic", CirconusCheckSearchTag: "service:nomadic", + CirconusCheckDisplayName: "node1:nomadic", + CirconusCheckTags: "cat1:tag1,cat2:tag2", CirconusBrokerID: "0", CirconusBrokerSelectTag: "dc:dc1", }, @@ -162,6 +164,8 @@ func TestConfig_Merge(t *testing.T) { CirconusCheckForceMetricActivation: "false", CirconusCheckInstanceID: "node2:nomad", CirconusCheckSearchTag: "service:nomad", + CirconusCheckDisplayName: "node2:nomad", + CirconusCheckTags: "cat1:tag1,cat2:tag2", CirconusBrokerID: "1", CirconusBrokerSelectTag: "dc:dc2", }, diff --git a/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/check.go b/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/check.go index 17b74acdf..201ef1e0c 100644 --- a/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/check.go +++ b/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/check.go @@ -29,21 +29,41 @@ func (cm *CheckManager) UpdateCheck(newMetrics map[string]*api.CheckBundleMetric return } + // only if there is *something* to update + if !cm.forceCheckUpdate && len(newMetrics) == 0 && len(cm.metricTags) == 0 { + return + } + + // refresh check bundle (in case there were changes made by other apps or in UI) + checkBundle, err := cm.apih.FetchCheckBundleByCID(api.CIDType(cm.checkBundle.Cid)) + if err != nil { + cm.Log.Printf("[ERROR] unable to fetch up-to-date check bundle %v", err) + return + } + cm.cbmu.Lock() + cm.checkBundle = checkBundle + cm.cbmu.Unlock() + cm.addNewMetrics(newMetrics) if len(cm.metricTags) > 0 { + // note: if a tag has been added (queued) for a metric which never gets sent + // the tags will be discarded. (setting tags does not *create* metrics.) for metricName, metricTags := range cm.metricTags { - // note: if a tag has been added (queued) for a metric which never gets sent - // the tags will be discarded. (setting tags does not *create* metrics.) - cm.AddMetricTags(metricName, metricTags, false) + for metricIdx, metric := range cm.checkBundle.Metrics { + if metric.Name == metricName { + cm.checkBundle.Metrics[metricIdx].Tags = metricTags + break + } + } cm.mtmu.Lock() delete(cm.metricTags, metricName) cm.mtmu.Unlock() } + cm.forceCheckUpdate = true } if cm.forceCheckUpdate { - newCheckBundle, err := cm.apih.UpdateCheckBundle(cm.checkBundle) if err != nil { cm.Log.Printf("[ERROR] updating check bundle %v", err) diff --git a/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/metrics.go b/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/metrics.go index f93a6f2a1..49b7c9457 100644 --- a/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/metrics.go +++ b/vendor/github.com/circonus-labs/circonus-gometrics/checkmgr/metrics.go @@ -37,58 +37,38 @@ func (cm *CheckManager) AddMetricTags(metricName string, tags []string, appendTa return tagsUpdated } - metricFound := false + if _, exists := cm.metricTags[metricName]; !exists { + foundMetric := false - for metricIdx, metric := range cm.checkBundle.Metrics { - if metric.Name == metricName { - metricFound = true - numNewTags := countNewTags(metric.Tags, tags) - - if numNewTags == 0 { - if appendTags { - break // no new tags to add - } else if len(metric.Tags) == len(tags) { - break // no new tags and old/new same length - } + for _, metric := range cm.checkBundle.Metrics { + if metric.Name == metricName { + foundMetric = true + cm.metricTags[metricName] = metric.Tags + break } + } - if appendTags { - metric.Tags = append(metric.Tags, tags...) - } else { - metric.Tags = tags - } - - cm.cbmu.Lock() - cm.checkBundle.Metrics[metricIdx] = metric - cm.cbmu.Unlock() - - tagsUpdated = true + if !foundMetric { + cm.metricTags[metricName] = []string{} } } - if tagsUpdated { - if cm.Debug { - action := "Set" - if appendTags { - action = "Added" - } - cm.Log.Printf("[DEBUG] %s metric tag(s) %s %v\n", action, metricName, tags) + action := "no new" + if appendTags { + numNewTags := countNewTags(cm.metricTags[metricName], tags) + if numNewTags > 0 { + action = "Added" + cm.metricTags[metricName] = append(cm.metricTags[metricName], tags...) + tagsUpdated = true } - cm.cbmu.Lock() - cm.forceCheckUpdate = true - cm.cbmu.Unlock() } else { - if !metricFound { - if _, exists := cm.metricTags[metricName]; !exists { - if cm.Debug { - cm.Log.Printf("[DEBUG] Queing metric tag(s) %s %v\n", metricName, tags) - } - // queue the tags, the metric is new (e.g. not in the check yet) - cm.mtmu.Lock() - cm.metricTags[metricName] = append(cm.metricTags[metricName], tags...) - cm.mtmu.Unlock() - } - } + action = "Set" + cm.metricTags[metricName] = tags + tagsUpdated = true + } + + if cm.Debug { + cm.Log.Printf("[DEBUG] %s metric tag(s) %s %v\n", action, metricName, tags) } return tagsUpdated @@ -103,6 +83,7 @@ func (cm *CheckManager) addNewMetrics(newMetrics map[string]*api.CheckBundleMetr } cm.cbmu.Lock() + defer cm.cbmu.Unlock() numCurrMetrics := len(cm.checkBundle.Metrics) numNewMetrics := len(newMetrics) @@ -126,8 +107,6 @@ func (cm *CheckManager) addNewMetrics(newMetrics map[string]*api.CheckBundleMetr cm.forceCheckUpdate = true } - cm.cbmu.Unlock() - return updatedCheckBundle } diff --git a/vendor/github.com/circonus-labs/circonusllhist/circonusllhist.go b/vendor/github.com/circonus-labs/circonusllhist/circonusllhist.go index cf4f482c1..119a45408 100644 --- a/vendor/github.com/circonus-labs/circonusllhist/circonusllhist.go +++ b/vendor/github.com/circonus-labs/circonusllhist/circonusllhist.go @@ -15,7 +15,7 @@ import ( ) const ( - DEFAULT_HIST_SIZE = int16(100) + DEFAULT_HIST_SIZE = uint16(100) ) var power_of_ten = [...]float64{ @@ -70,6 +70,14 @@ func NewBinFromFloat64(d float64) *Bin { hb.SetFromFloat64(d) return hb } + +type FastL2 struct { + l1, l2 int +} + +func (hb *Bin) fastl2() FastL2 { + return FastL2{l1: int(uint8(hb.exp)), l2: int(uint8(hb.val))} +} func (hb *Bin) SetFromFloat64(d float64) *Bin { hb.val = -1 if math.IsInf(d, 0) || math.IsNaN(d) { @@ -117,10 +125,7 @@ func (hb *Bin) SetFromFloat64(d float64) *Bin { return hb } func (hb *Bin) PowerOfTen() float64 { - idx := int(hb.exp) - if idx < 0 { - idx = 256 + idx - } + idx := int(uint8(hb.exp)) return power_of_ten[idx] } @@ -183,69 +188,58 @@ func (hb *Bin) Left() float64 { } func (h1 *Bin) Compare(h2 *Bin) int { - if h1.val == h2.val && h1.exp == h2.exp { - return 0 + var v1, v2 int + + // slide exp positive, + // shift by size of val + // multiple by (val != 0) + // then add or subtract val accordingly + + if h1.val >= 0 { + v1 = ((int(h1.exp)+256)<<8)*int(((h1.val|(^h1.val+1))>>8)&1) + int(h1.val) + } else { + v1 = ((int(h1.exp)+256)<<8)*int(((h1.val|(^h1.val+1))>>8)&1) - int(h1.val) } - if h1.val == -1 { - return 1 + if h2.val >= 0 { + v2 = ((int(h2.exp)+256)<<8)*int(((h2.val|(^h2.val+1))>>8)&1) + int(h2.val) + } else { + v2 = ((int(h2.exp)+256)<<8)*int(((h2.val|(^h2.val+1))>>8)&1) - int(h2.val) } - if h2.val == -1 { - return -1 - } - if h1.val == 0 { - if h2.val > 0 { - return 1 - } - return -1 - } - if h2.val == 0 { - if h1.val < 0 { - return 1 - } - return -1 - } - if h1.val < 0 && h2.val > 0 { - return 1 - } - if h1.val > 0 && h2.val < 0 { - return -1 - } - if h1.exp == h2.exp { - if h1.val < h2.val { - return 1 - } - return -1 - } - if h1.exp > h2.exp { - if h1.val < 0 { - return 1 - } - return -1 - } - if h1.exp < h2.exp { - if h1.val < 0 { - return -1 - } - return 1 - } - return 0 + + // return the difference + return v2 - v1 } // This histogram structure tracks values are two decimal digits of precision // with a bounded error that remains bounded upon composition type Histogram struct { - mutex sync.Mutex bvs []Bin - used int16 - allocd int16 + used uint16 + allocd uint16 + + lookup [256][]uint16 + + mutex sync.Mutex + useLocks bool } // New returns a new Histogram func New() *Histogram { return &Histogram{ - allocd: DEFAULT_HIST_SIZE, - used: 0, - bvs: make([]Bin, DEFAULT_HIST_SIZE), + allocd: DEFAULT_HIST_SIZE, + used: 0, + bvs: make([]Bin, DEFAULT_HIST_SIZE), + useLocks: true, + } +} + +// New returns a Histogram without locking +func NewNoLocks() *Histogram { + return &Histogram{ + allocd: DEFAULT_HIST_SIZE, + used: 0, + bvs: make([]Bin, DEFAULT_HIST_SIZE), + useLocks: false, } } @@ -266,9 +260,24 @@ func (h *Histogram) Mean() float64 { // Reset forgets all bins in the histogram (they remain allocated) func (h *Histogram) Reset() { - h.mutex.Lock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } + for i := 0; i < 256; i++ { + if h.lookup[i] != nil { + for j := range h.lookup[i] { + h.lookup[i][j] = 0 + } + } + } h.used = 0 - h.mutex.Unlock() +} + +// RecordIntScale records an integer scaler value, returning an error if the +// value is out of range. +func (h *Histogram) RecordIntScale(val, scale int) error { + return h.RecordIntScales(val, scale, 1) } // RecordValue records the given value, returning an error if the value is out @@ -304,13 +313,19 @@ func (h *Histogram) RecordCorrectedValue(v, expectedInterval int64) error { } // find where a new bin should go -func (h *Histogram) InternalFind(hb *Bin) (bool, int16) { +func (h *Histogram) InternalFind(hb *Bin) (bool, uint16) { if h.used == 0 { return false, 0 } + f2 := hb.fastl2() + if h.lookup[f2.l1] != nil { + if idx := h.lookup[f2.l1][f2.l2]; idx != 0 { + return true, idx - 1 + } + } rv := -1 - idx := int16(0) - l := int16(0) + idx := uint16(0) + l := uint16(0) r := h.used - 1 for l < r { check := (r + l) / 2 @@ -339,10 +354,9 @@ func (h *Histogram) InternalFind(hb *Bin) (bool, int16) { } func (h *Histogram) InsertBin(hb *Bin, count int64) uint64 { - h.mutex.Lock() - defer h.mutex.Unlock() - if count == 0 { - return 0 + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() } found, idx := h.InternalFind(hb) if !found { @@ -363,13 +377,20 @@ func (h *Histogram) InsertBin(hb *Bin, count int64) uint64 { h.bvs[idx].exp = hb.exp h.bvs[idx].count = uint64(count) h.used++ + for i := idx; i < h.used; i++ { + f2 := h.bvs[i].fastl2() + if h.lookup[f2.l1] == nil { + h.lookup[f2.l1] = make([]uint16, 256) + } + h.lookup[f2.l1][f2.l2] = uint16(i) + 1 + } return h.bvs[idx].count } var newval uint64 - if count < 0 { - newval = h.bvs[idx].count - uint64(-count) - } else { + if count >= 0 { newval = h.bvs[idx].count + uint64(count) + } else { + newval = h.bvs[idx].count - uint64(-count) } if newval < h.bvs[idx].count { //rolled newval = ^uint64(0) @@ -378,6 +399,39 @@ func (h *Histogram) InsertBin(hb *Bin, count int64) uint64 { return newval - h.bvs[idx].count } +// RecordIntScales records n occurrences of the given value, returning an error if +// the value is out of range. +func (h *Histogram) RecordIntScales(val, scale int, n int64) error { + sign := 1 + if val == 0 { + scale = 0 + } else { + if val < 0 { + val = 0 - val + sign = -1 + } + if val < 10 { + val *= 10 + scale -= 1 + } + for val > 100 { + val /= 10 + scale++ + } + } + if scale < -128 { + val = 0 + scale = 0 + } else if scale > 127 { + val = 0xff + scale = 0 + } + val *= sign + hb := Bin{val: int8(val), exp: int8(scale), count: 0} + h.InsertBin(&hb, n) + return nil +} + // RecordValues records n occurrences of the given value, returning an error if // the value is out of range. func (h *Histogram) RecordValues(v float64, n int64) error { @@ -389,11 +443,13 @@ func (h *Histogram) RecordValues(v float64, n int64) error { // Approximate mean func (h *Histogram) ApproxMean() float64 { - h.mutex.Lock() - defer h.mutex.Unlock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } divisor := 0.0 sum := 0.0 - for i := int16(0); i < h.used; i++ { + for i := uint16(0); i < h.used; i++ { midpoint := h.bvs[i].Midpoint() cardinality := float64(h.bvs[i].count) divisor += cardinality @@ -407,10 +463,12 @@ func (h *Histogram) ApproxMean() float64 { // Approximate sum func (h *Histogram) ApproxSum() float64 { - h.mutex.Lock() - defer h.mutex.Unlock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } sum := 0.0 - for i := int16(0); i < h.used; i++ { + for i := uint16(0); i < h.used; i++ { midpoint := h.bvs[i].Midpoint() cardinality := float64(h.bvs[i].count) sum += midpoint * cardinality @@ -419,10 +477,12 @@ func (h *Histogram) ApproxSum() float64 { } func (h *Histogram) ApproxQuantile(q_in []float64) ([]float64, error) { - h.mutex.Lock() - defer h.mutex.Unlock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } q_out := make([]float64, len(q_in)) - i_q, i_b := 0, int16(0) + i_q, i_b := 0, uint16(0) total_cnt, bin_width, bin_left, lower_cnt, upper_cnt := 0.0, 0.0, 0.0, 0.0, 0.0 if len(q_in) == 0 { return q_out, nil @@ -485,8 +545,10 @@ func (h *Histogram) ApproxQuantile(q_in []float64) ([]float64, error) { // ValueAtQuantile returns the recorded value at the given quantile (0..1). func (h *Histogram) ValueAtQuantile(q float64) float64 { - h.mutex.Lock() - defer h.mutex.Unlock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } q_in := make([]float64, 1) q_in[0] = q q_out, err := h.ApproxQuantile(q_in) @@ -505,16 +567,20 @@ func (h *Histogram) SignificantFigures() int64 { // Equals returns true if the two Histograms are equivalent, false if not. func (h *Histogram) Equals(other *Histogram) bool { - h.mutex.Lock() - other.mutex.Lock() - defer h.mutex.Unlock() - defer other.mutex.Unlock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } + if other.useLocks { + other.mutex.Lock() + defer other.mutex.Unlock() + } switch { case h.used != other.used: return false default: - for i := int16(0); i < h.used; i++ { + for i := uint16(0); i < h.used; i++ { if h.bvs[i].Compare(&other.bvs[i]) != 0 { return false } @@ -527,8 +593,10 @@ func (h *Histogram) Equals(other *Histogram) bool { } func (h *Histogram) CopyAndReset() *Histogram { - h.mutex.Lock() - defer h.mutex.Unlock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } newhist := &Histogram{ allocd: h.allocd, used: h.used, @@ -537,11 +605,20 @@ func (h *Histogram) CopyAndReset() *Histogram { h.allocd = DEFAULT_HIST_SIZE h.bvs = make([]Bin, DEFAULT_HIST_SIZE) h.used = 0 + for i := 0; i < 256; i++ { + if h.lookup[i] != nil { + for j := range h.lookup[i] { + h.lookup[i][j] = 0 + } + } + } return newhist } func (h *Histogram) DecStrings() []string { - h.mutex.Lock() - defer h.mutex.Unlock() + if h.useLocks { + h.mutex.Lock() + defer h.mutex.Unlock() + } out := make([]string, h.used) for i, bin := range h.bvs[0:h.used] { var buffer bytes.Buffer diff --git a/vendor/vendor.json b/vendor/vendor.json index aab53abe1..86567ffbc 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -202,26 +202,26 @@ { "checksumSHA1": "szvY4u7TlXkrQ3PW8wmyJaIFy0U=", "path": "github.com/circonus-labs/circonus-gometrics", - "revision": "97c824a6a4418e3021f93624339fbd4ac8cf36a4", - "revisionTime": "2016-11-08T23:29:31Z" + "revision": "d17a8420c36e800fcb46bbd4d2a15b93c68605ea", + "revisionTime": "2016-11-09T19:23:37Z" }, { "checksumSHA1": "WUE6oF152uN5FcLmmq+nO3Yl7pU=", "path": "github.com/circonus-labs/circonus-gometrics/api", - "revision": "97c824a6a4418e3021f93624339fbd4ac8cf36a4", - "revisionTime": "2016-11-08T23:29:31Z" + "revision": "d17a8420c36e800fcb46bbd4d2a15b93c68605ea", + "revisionTime": "2016-11-09T19:23:37Z" }, { - "checksumSHA1": "Yn+yKETM1P74HXx5BVl5oUl2LMw=", + "checksumSHA1": "beRBHHy2+V6Ht4cACIMmZOCnzgg=", "path": "github.com/circonus-labs/circonus-gometrics/checkmgr", - "revision": "97c824a6a4418e3021f93624339fbd4ac8cf36a4", - "revisionTime": "2016-11-08T23:29:31Z" + "revision": "d17a8420c36e800fcb46bbd4d2a15b93c68605ea", + "revisionTime": "2016-11-09T19:23:37Z" }, { - "checksumSHA1": "C4Z7+l5GOpOCW5DcvNYzheGvQRE=", + "checksumSHA1": "eYWKyMvUWZpmuXjDEIGy9lBddK0=", "path": "github.com/circonus-labs/circonusllhist", - "revision": "d724266ae5270ae8b87a5d2e8081f04e307c3c18", - "revisionTime": "2016-05-26T04:38:13Z" + "revision": "f3bb61c09a65a1bb5833219937fe4e7042dadab4", + "revisionTime": "2016-11-09T20:01:07Z" }, { "path": "github.com/davecgh/go-spew/spew", diff --git a/website/source/docs/agent/configuration/telemetry.html.md b/website/source/docs/agent/configuration/telemetry.html.md index bbab67a24..896fd4822 100644 --- a/website/source/docs/agent/configuration/telemetry.html.md +++ b/website/source/docs/agent/configuration/telemetry.html.md @@ -135,6 +135,13 @@ These `telemetry` parameters apply to search results when neither a Submission URL or Check ID is provided. By default, this is set to service:app (e.g. "service:nomad"). +- `circonus_check_display_name` `(string: "")` - Specifies a name to give a + check when it is created. This name is displayed in the Circonus UI Checks + list. + +- `circonus_check_tags` `(string: "")` - Comma separated list of additional + tags to add to a check when it is created. + - `circonus_broker_id` `(string: "")` - Specifies the ID of a specific Circonus Broker to use when creating a new check. The numeric portion of `broker._cid` field in a Broker API object. If metric management is enabled and neither a