forked from mirrors/statsd_exporter
merge with upstream master
This commit is contained in:
commit
74975b8411
9 changed files with 113 additions and 43 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
## v0.4.0 / 2017-05-12
|
||||||
|
|
||||||
|
* [IMPROVEMENT] Improve mapping configuration parser #61
|
||||||
|
* [IMPROVEMENT] Add increment/decrement support to Gauges #65
|
||||||
|
* [BUGFIX] Tolerate more forms of broken lines from StatsD #48
|
||||||
|
* [BUGFIX] Skip metrics with invalid utf8 #50
|
||||||
|
* [BUGFIX] ListenAndServe now fails on exit #58
|
||||||
|
|
||||||
## 0.3.0 / 2016-05-05
|
## 0.3.0 / 2016-05-05
|
||||||
|
|
||||||
* [CHANGE] Drop `_count` suffix for `loaded_mappings` metric (#41)
|
* [CHANGE] Drop `_count` suffix for `loaded_mappings` metric (#41)
|
||||||
|
|
|
@ -88,6 +88,7 @@ with `-statsd.add-suffix=false`.
|
||||||
|
|
||||||
An example mapping configuration with `-statsd.add-suffix=false`:
|
An example mapping configuration with `-statsd.add-suffix=false`:
|
||||||
|
|
||||||
|
# comments are allowed
|
||||||
test.dispatcher.*.*.*
|
test.dispatcher.*.*.*
|
||||||
name="dispatcher_events_total"
|
name="dispatcher_events_total"
|
||||||
processor="$1"
|
processor="$1"
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
0.3.0
|
0.4.0
|
||||||
|
|
|
@ -198,6 +198,21 @@ func TestHandlePacket(t *testing.T) {
|
||||||
labels: map[string]string{},
|
labels: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
name: "timings with sampling factor",
|
||||||
|
in: "foo.timing:0.5|ms|@0.1",
|
||||||
|
out: Events{
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
&TimerEvent{metricName: "foo.timing", value: 0.5, labels: map[string]string{}},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: "bad line",
|
name: "bad line",
|
||||||
in: "foo",
|
in: "foo",
|
||||||
|
|
|
@ -48,6 +48,7 @@ deployment:
|
||||||
owner: prometheus
|
owner: prometheus
|
||||||
commands:
|
commands:
|
||||||
- promu crossbuild tarballs
|
- promu crossbuild tarballs
|
||||||
|
- promu checksum .tarballs
|
||||||
- promu release .tarballs
|
- promu release .tarballs
|
||||||
- mkdir $CIRCLE_ARTIFACTS/releases/ && cp -a .tarballs/* $CIRCLE_ARTIFACTS/releases/
|
- mkdir $CIRCLE_ARTIFACTS/releases/ && cp -a .tarballs/* $CIRCLE_ARTIFACTS/releases/
|
||||||
- docker login -e $DOCKER_EMAIL -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
|
- docker login -e $DOCKER_EMAIL -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
|
||||||
|
|
113
exporter.go
113
exporter.go
|
@ -69,7 +69,7 @@ func NewCounterContainer() *CounterContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CounterContainer) Get(metricName string, labels prometheus.Labels) prometheus.Counter {
|
func (c *CounterContainer) Get(metricName string, labels prometheus.Labels) (prometheus.Counter, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
hash := hashNameAndLabels(metricName, labels)
|
||||||
counter, ok := c.Elements[hash]
|
counter, ok := c.Elements[hash]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -78,12 +78,12 @@ func (c *CounterContainer) Get(metricName string, labels prometheus.Labels) prom
|
||||||
Help: defaultHelp,
|
Help: defaultHelp,
|
||||||
ConstLabels: labels,
|
ConstLabels: labels,
|
||||||
})
|
})
|
||||||
c.Elements[hash] = counter
|
|
||||||
if err := prometheus.Register(counter); err != nil {
|
if err := prometheus.Register(counter); err != nil {
|
||||||
log.Fatalf(regErrF, metricName, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
c.Elements[hash] = counter
|
||||||
}
|
}
|
||||||
return counter
|
return counter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type GaugeContainer struct {
|
type GaugeContainer struct {
|
||||||
|
@ -96,7 +96,7 @@ func NewGaugeContainer() *GaugeContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GaugeContainer) Get(metricName string, labels prometheus.Labels) prometheus.Gauge {
|
func (c *GaugeContainer) Get(metricName string, labels prometheus.Labels) (prometheus.Gauge, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
hash := hashNameAndLabels(metricName, labels)
|
||||||
gauge, ok := c.Elements[hash]
|
gauge, ok := c.Elements[hash]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -105,12 +105,12 @@ func (c *GaugeContainer) Get(metricName string, labels prometheus.Labels) promet
|
||||||
Help: defaultHelp,
|
Help: defaultHelp,
|
||||||
ConstLabels: labels,
|
ConstLabels: labels,
|
||||||
})
|
})
|
||||||
c.Elements[hash] = gauge
|
|
||||||
if err := prometheus.Register(gauge); err != nil {
|
if err := prometheus.Register(gauge); err != nil {
|
||||||
log.Fatalf(regErrF, metricName, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
c.Elements[hash] = gauge
|
||||||
}
|
}
|
||||||
return gauge
|
return gauge, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SummaryContainer struct {
|
type SummaryContainer struct {
|
||||||
|
@ -123,7 +123,7 @@ func NewSummaryContainer() *SummaryContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels) prometheus.Summary {
|
func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels) (prometheus.Summary, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
hash := hashNameAndLabels(metricName, labels)
|
||||||
summary, ok := c.Elements[hash]
|
summary, ok := c.Elements[hash]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -133,12 +133,12 @@ func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels) prom
|
||||||
Help: defaultHelp,
|
Help: defaultHelp,
|
||||||
ConstLabels: labels,
|
ConstLabels: labels,
|
||||||
})
|
})
|
||||||
c.Elements[hash] = summary
|
|
||||||
if err := prometheus.Register(summary); err != nil {
|
if err := prometheus.Register(summary); err != nil {
|
||||||
log.Fatalf(regErrF, metricName, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
c.Elements[hash] = summary
|
||||||
}
|
}
|
||||||
return summary
|
return summary, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type HistogramContainer struct {
|
type HistogramContainer struct {
|
||||||
|
@ -153,7 +153,7 @@ func NewHistogramContainer(mapper *metricMapper) *HistogramContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HistogramContainer) Get(metricName string, labels prometheus.Labels, mapping *metricMapping) prometheus.Histogram {
|
func (c *HistogramContainer) Get(metricName string, labels prometheus.Labels, mapping *metricMapping) (prometheus.Histogram, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
hash := hashNameAndLabels(metricName, labels)
|
||||||
histogram, ok := c.Elements[hash]
|
histogram, ok := c.Elements[hash]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -170,10 +170,10 @@ func (c *HistogramContainer) Get(metricName string, labels prometheus.Labels, ma
|
||||||
})
|
})
|
||||||
c.Elements[hash] = histogram
|
c.Elements[hash] = histogram
|
||||||
if err := prometheus.Register(histogram); err != nil {
|
if err := prometheus.Register(histogram); err != nil {
|
||||||
log.Fatalf(regErrF, metricName, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return histogram
|
return histogram, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Event interface {
|
type Event interface {
|
||||||
|
@ -269,10 +269,6 @@ func (b *Exporter) Listen(e <-chan Events) {
|
||||||
|
|
||||||
switch ev := event.(type) {
|
switch ev := event.(type) {
|
||||||
case *CounterEvent:
|
case *CounterEvent:
|
||||||
counter := b.Counters.Get(
|
|
||||||
b.suffix(metricName, "counter"),
|
|
||||||
prometheusLabels,
|
|
||||||
)
|
|
||||||
// We don't accept negative values for counters. Incrementing the counter with a negative number
|
// We don't accept negative values for counters. Incrementing the counter with a negative number
|
||||||
// will cause the exporter to panic. Instead we will warn and continue to the next event.
|
// will cause the exporter to panic. Instead we will warn and continue to the next event.
|
||||||
if event.Value() < 0.0 {
|
if event.Value() < 0.0 {
|
||||||
|
@ -280,23 +276,37 @@ func (b *Exporter) Listen(e <-chan Events) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
counter.Add(event.Value())
|
counter, err := b.Counters.Get(
|
||||||
|
b.suffix(metricName, "counter"),
|
||||||
|
prometheusLabels,
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
counter.Add(event.Value())
|
||||||
|
|
||||||
eventStats.WithLabelValues("counter").Inc()
|
eventStats.WithLabelValues("counter").Inc()
|
||||||
|
} else {
|
||||||
|
log.Errorf(regErrF, metricName, err)
|
||||||
|
conflictingEventStats.WithLabelValues("counter").Inc()
|
||||||
|
}
|
||||||
|
|
||||||
case *GaugeEvent:
|
case *GaugeEvent:
|
||||||
gauge := b.Gauges.Get(
|
gauge, err := b.Gauges.Get(
|
||||||
b.suffix(metricName, "gauge"),
|
b.suffix(metricName, "gauge"),
|
||||||
prometheusLabels,
|
prometheusLabels,
|
||||||
)
|
)
|
||||||
|
|
||||||
if ev.relative {
|
if err == nil {
|
||||||
gauge.Add(event.Value())
|
if ev.relative {
|
||||||
} else {
|
gauge.Add(event.Value())
|
||||||
gauge.Set(event.Value())
|
} else {
|
||||||
}
|
gauge.Set(event.Value())
|
||||||
|
}
|
||||||
|
|
||||||
eventStats.WithLabelValues("gauge").Inc()
|
eventStats.WithLabelValues("gauge").Inc()
|
||||||
|
} else {
|
||||||
|
log.Errorf(regErrF, metricName, err)
|
||||||
|
conflictingEventStats.WithLabelValues("gauge").Inc()
|
||||||
|
}
|
||||||
|
|
||||||
case *TimerEvent:
|
case *TimerEvent:
|
||||||
timerType := ""
|
timerType := ""
|
||||||
|
@ -308,22 +318,32 @@ func (b *Exporter) Listen(e <-chan Events) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if timerType == "histogram" {
|
if timerType == "histogram" {
|
||||||
histogram := b.Histograms.Get(
|
histogram, err := b.Histograms.Get(
|
||||||
b.suffix(metricName, "timer"),
|
b.suffix(metricName, "timer"),
|
||||||
prometheusLabels,
|
prometheusLabels,
|
||||||
mapping,
|
mapping,
|
||||||
)
|
)
|
||||||
histogram.Observe(event.Value())
|
if err == nil {
|
||||||
|
histogram.Observe(event.Value())
|
||||||
|
eventStats.WithLabelValues("timer").Inc()
|
||||||
|
} else {
|
||||||
|
log.Errorf(regErrF, metricName, err)
|
||||||
|
conflictingEventStats.WithLabelValues("timer").Inc()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
summary := b.Summaries.Get(
|
summary, err := b.Summaries.Get(
|
||||||
b.suffix(metricName, "timer"),
|
b.suffix(metricName, "timer"),
|
||||||
prometheusLabels,
|
prometheusLabels,
|
||||||
)
|
)
|
||||||
summary.Observe(event.Value())
|
if err == nil {
|
||||||
|
summary.Observe(event.Value())
|
||||||
|
eventStats.WithLabelValues("timer").Inc()
|
||||||
|
} else {
|
||||||
|
log.Errorf(regErrF, metricName, err)
|
||||||
|
conflictingEventStats.WithLabelValues("timer").Inc()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventStats.WithLabelValues("timer").Inc()
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Errorln("Unsupported event type")
|
log.Errorln("Unsupported event type")
|
||||||
eventStats.WithLabelValues("illegal").Inc()
|
eventStats.WithLabelValues("illegal").Inc()
|
||||||
|
@ -450,6 +470,7 @@ func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multiplyEvents := 1
|
||||||
labels := map[string]string{}
|
labels := map[string]string{}
|
||||||
if len(components) >= 3 {
|
if len(components) >= 3 {
|
||||||
for _, component := range components[2:] {
|
for _, component := range components[2:] {
|
||||||
|
@ -463,9 +484,10 @@ func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
||||||
for _, component := range components[2:] {
|
for _, component := range components[2:] {
|
||||||
switch component[0] {
|
switch component[0] {
|
||||||
case '@':
|
case '@':
|
||||||
if statType != "c" {
|
if statType != "c" && statType != "ms" {
|
||||||
log.Errorln("Illegal sampling factor for non-counter metric on line", line)
|
log.Errorln("Illegal sampling factor for non-counter metric on line", line)
|
||||||
networkStats.WithLabelValues("illegal_sample_factor").Inc()
|
networkStats.WithLabelValues("illegal_sample_factor").Inc()
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
samplingFactor, err = strconv.ParseFloat(component[1:], 64)
|
samplingFactor, err = strconv.ParseFloat(component[1:], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -475,7 +497,12 @@ func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
||||||
if samplingFactor == 0 {
|
if samplingFactor == 0 {
|
||||||
samplingFactor = 1
|
samplingFactor = 1
|
||||||
}
|
}
|
||||||
value /= samplingFactor
|
|
||||||
|
if statType == "c" {
|
||||||
|
value /= samplingFactor
|
||||||
|
} else if statType == "ms" {
|
||||||
|
multiplyEvents = int(1 / samplingFactor)
|
||||||
|
}
|
||||||
case '#':
|
case '#':
|
||||||
labels = parseDogStatsDTagsToLabels(component)
|
labels = parseDogStatsDTagsToLabels(component)
|
||||||
default:
|
default:
|
||||||
|
@ -486,13 +513,15 @@ func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event, err := buildEvent(statType, metric, value, relative, labels)
|
for i := 0; i < multiplyEvents; i++ {
|
||||||
if err != nil {
|
event, err := buildEvent(statType, metric, value, relative, labels)
|
||||||
log.Errorf("Error building event on line %s: %s", line, err)
|
if err != nil {
|
||||||
networkStats.WithLabelValues("illegal_event").Inc()
|
log.Errorf("Error building event on line %s: %s", line, err)
|
||||||
continue
|
networkStats.WithLabelValues("illegal_event").Inc()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
events = append(events, event)
|
||||||
}
|
}
|
||||||
events = append(events, event)
|
|
||||||
networkStats.WithLabelValues("legal").Inc()
|
networkStats.WithLabelValues("legal").Inc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,11 @@ func (m *metricMapper) initFromString(fileContents string) error {
|
||||||
for i, line := range lines {
|
for i, line := range lines {
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
// skip comments
|
||||||
|
if strings.HasPrefix(line, "#") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch state {
|
switch state {
|
||||||
case SEARCHING:
|
case SEARCHING:
|
||||||
if line == "" {
|
if line == "" {
|
||||||
|
|
|
@ -28,11 +28,14 @@ func TestMetricMapper(t *testing.T) {
|
||||||
// Config with several mapping definitions.
|
// Config with several mapping definitions.
|
||||||
{
|
{
|
||||||
config: `
|
config: `
|
||||||
|
# this is a comment
|
||||||
|
# this is another
|
||||||
test.dispatcher.*.*.*
|
test.dispatcher.*.*.*
|
||||||
name="dispatch_events"
|
name="dispatch_events"
|
||||||
processor="$1"
|
processor="$1"
|
||||||
action="$2"
|
action="$2"
|
||||||
result="$3"
|
result="$3"
|
||||||
|
# here is a third
|
||||||
job="test_dispatcher"
|
job="test_dispatcher"
|
||||||
|
|
||||||
test.my-dispatch-host01.name.dispatcher.*.*.*
|
test.my-dispatch-host01.name.dispatcher.*.*.*
|
||||||
|
|
|
@ -47,6 +47,13 @@ var (
|
||||||
Name: "statsd_exporter_loaded_mappings",
|
Name: "statsd_exporter_loaded_mappings",
|
||||||
Help: "The current number of configured metric mappings.",
|
Help: "The current number of configured metric mappings.",
|
||||||
})
|
})
|
||||||
|
conflictingEventStats = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "statsd_exporter_events_conflict_total",
|
||||||
|
Help: "The total number of StatsD events with conflicting names.",
|
||||||
|
},
|
||||||
|
[]string{"type"},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -54,4 +61,5 @@ func init() {
|
||||||
prometheus.MustRegister(networkStats)
|
prometheus.MustRegister(networkStats)
|
||||||
prometheus.MustRegister(configLoads)
|
prometheus.MustRegister(configLoads)
|
||||||
prometheus.MustRegister(mappingsCount)
|
prometheus.MustRegister(mappingsCount)
|
||||||
|
prometheus.MustRegister(conflictingEventStats)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue