435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
233 lines
7 KiB
Go
233 lines
7 KiB
Go
package statsd
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
gaugeSymbol = []byte("g")
|
|
countSymbol = []byte("c")
|
|
histogramSymbol = []byte("h")
|
|
distributionSymbol = []byte("d")
|
|
setSymbol = []byte("s")
|
|
timingSymbol = []byte("ms")
|
|
)
|
|
|
|
func appendHeader(buffer []byte, namespace string, name string) []byte {
|
|
if namespace != "" {
|
|
buffer = append(buffer, namespace...)
|
|
}
|
|
buffer = append(buffer, name...)
|
|
buffer = append(buffer, ':')
|
|
return buffer
|
|
}
|
|
|
|
func appendRate(buffer []byte, rate float64) []byte {
|
|
if rate < 1 {
|
|
buffer = append(buffer, "|@"...)
|
|
buffer = strconv.AppendFloat(buffer, rate, 'f', -1, 64)
|
|
}
|
|
return buffer
|
|
}
|
|
|
|
func appendWithoutNewlines(buffer []byte, s string) []byte {
|
|
// fastpath for strings without newlines
|
|
if strings.IndexByte(s, '\n') == -1 {
|
|
return append(buffer, s...)
|
|
}
|
|
|
|
for _, b := range []byte(s) {
|
|
if b != '\n' {
|
|
buffer = append(buffer, b)
|
|
}
|
|
}
|
|
return buffer
|
|
}
|
|
|
|
func appendTags(buffer []byte, globalTags []string, tags []string) []byte {
|
|
if len(globalTags) == 0 && len(tags) == 0 {
|
|
return buffer
|
|
}
|
|
buffer = append(buffer, "|#"...)
|
|
firstTag := true
|
|
|
|
for _, tag := range globalTags {
|
|
if !firstTag {
|
|
buffer = append(buffer, ',')
|
|
}
|
|
buffer = appendWithoutNewlines(buffer, tag)
|
|
firstTag = false
|
|
}
|
|
for _, tag := range tags {
|
|
if !firstTag {
|
|
buffer = append(buffer, ',')
|
|
}
|
|
buffer = appendWithoutNewlines(buffer, tag)
|
|
firstTag = false
|
|
}
|
|
return buffer
|
|
}
|
|
|
|
func appendFloatMetric(buffer []byte, typeSymbol []byte, namespace string, globalTags []string, name string, value float64, tags []string, rate float64, precision int) []byte {
|
|
buffer = appendHeader(buffer, namespace, name)
|
|
buffer = strconv.AppendFloat(buffer, value, 'f', precision, 64)
|
|
buffer = append(buffer, '|')
|
|
buffer = append(buffer, typeSymbol...)
|
|
buffer = appendRate(buffer, rate)
|
|
buffer = appendTags(buffer, globalTags, tags)
|
|
return buffer
|
|
}
|
|
|
|
func appendIntegerMetric(buffer []byte, typeSymbol []byte, namespace string, globalTags []string, name string, value int64, tags []string, rate float64) []byte {
|
|
buffer = appendHeader(buffer, namespace, name)
|
|
buffer = strconv.AppendInt(buffer, value, 10)
|
|
buffer = append(buffer, '|')
|
|
buffer = append(buffer, typeSymbol...)
|
|
buffer = appendRate(buffer, rate)
|
|
buffer = appendTags(buffer, globalTags, tags)
|
|
return buffer
|
|
}
|
|
|
|
func appendStringMetric(buffer []byte, typeSymbol []byte, namespace string, globalTags []string, name string, value string, tags []string, rate float64) []byte {
|
|
buffer = appendHeader(buffer, namespace, name)
|
|
buffer = append(buffer, value...)
|
|
buffer = append(buffer, '|')
|
|
buffer = append(buffer, typeSymbol...)
|
|
buffer = appendRate(buffer, rate)
|
|
buffer = appendTags(buffer, globalTags, tags)
|
|
return buffer
|
|
}
|
|
|
|
func appendGauge(buffer []byte, namespace string, globalTags []string, name string, value float64, tags []string, rate float64) []byte {
|
|
return appendFloatMetric(buffer, gaugeSymbol, namespace, globalTags, name, value, tags, rate, -1)
|
|
}
|
|
|
|
func appendCount(buffer []byte, namespace string, globalTags []string, name string, value int64, tags []string, rate float64) []byte {
|
|
return appendIntegerMetric(buffer, countSymbol, namespace, globalTags, name, value, tags, rate)
|
|
}
|
|
|
|
func appendHistogram(buffer []byte, namespace string, globalTags []string, name string, value float64, tags []string, rate float64) []byte {
|
|
return appendFloatMetric(buffer, histogramSymbol, namespace, globalTags, name, value, tags, rate, -1)
|
|
}
|
|
|
|
func appendDistribution(buffer []byte, namespace string, globalTags []string, name string, value float64, tags []string, rate float64) []byte {
|
|
return appendFloatMetric(buffer, distributionSymbol, namespace, globalTags, name, value, tags, rate, -1)
|
|
}
|
|
|
|
func appendSet(buffer []byte, namespace string, globalTags []string, name string, value string, tags []string, rate float64) []byte {
|
|
return appendStringMetric(buffer, setSymbol, namespace, globalTags, name, value, tags, rate)
|
|
}
|
|
|
|
func appendTiming(buffer []byte, namespace string, globalTags []string, name string, value float64, tags []string, rate float64) []byte {
|
|
return appendFloatMetric(buffer, timingSymbol, namespace, globalTags, name, value, tags, rate, 6)
|
|
}
|
|
|
|
func escapedEventTextLen(text string) int {
|
|
return len(text) + strings.Count(text, "\n")
|
|
}
|
|
|
|
func appendEscapedEventText(buffer []byte, text string) []byte {
|
|
for _, b := range []byte(text) {
|
|
if b != '\n' {
|
|
buffer = append(buffer, b)
|
|
} else {
|
|
buffer = append(buffer, "\\n"...)
|
|
}
|
|
}
|
|
return buffer
|
|
}
|
|
|
|
func appendEvent(buffer []byte, event Event, globalTags []string) []byte {
|
|
escapedTextLen := escapedEventTextLen(event.Text)
|
|
|
|
buffer = append(buffer, "_e{"...)
|
|
buffer = strconv.AppendInt(buffer, int64(len(event.Title)), 10)
|
|
buffer = append(buffer, ',')
|
|
buffer = strconv.AppendInt(buffer, int64(escapedTextLen), 10)
|
|
buffer = append(buffer, "}:"...)
|
|
buffer = append(buffer, event.Title...)
|
|
buffer = append(buffer, '|')
|
|
if escapedTextLen != len(event.Text) {
|
|
buffer = appendEscapedEventText(buffer, event.Text)
|
|
} else {
|
|
buffer = append(buffer, event.Text...)
|
|
}
|
|
|
|
if !event.Timestamp.IsZero() {
|
|
buffer = append(buffer, "|d:"...)
|
|
buffer = strconv.AppendInt(buffer, int64(event.Timestamp.Unix()), 10)
|
|
}
|
|
|
|
if len(event.Hostname) != 0 {
|
|
buffer = append(buffer, "|h:"...)
|
|
buffer = append(buffer, event.Hostname...)
|
|
}
|
|
|
|
if len(event.AggregationKey) != 0 {
|
|
buffer = append(buffer, "|k:"...)
|
|
buffer = append(buffer, event.AggregationKey...)
|
|
}
|
|
|
|
if len(event.Priority) != 0 {
|
|
buffer = append(buffer, "|p:"...)
|
|
buffer = append(buffer, event.Priority...)
|
|
}
|
|
|
|
if len(event.SourceTypeName) != 0 {
|
|
buffer = append(buffer, "|s:"...)
|
|
buffer = append(buffer, event.SourceTypeName...)
|
|
}
|
|
|
|
if len(event.AlertType) != 0 {
|
|
buffer = append(buffer, "|t:"...)
|
|
buffer = append(buffer, string(event.AlertType)...)
|
|
}
|
|
|
|
buffer = appendTags(buffer, globalTags, event.Tags)
|
|
return buffer
|
|
}
|
|
|
|
func appendEscapedServiceCheckText(buffer []byte, text string) []byte {
|
|
for i := 0; i < len(text); i++ {
|
|
if text[i] == '\n' {
|
|
buffer = append(buffer, "\\n"...)
|
|
} else if text[i] == 'm' && i+1 < len(text) && text[i+1] == ':' {
|
|
buffer = append(buffer, "m\\:"...)
|
|
i++
|
|
} else {
|
|
buffer = append(buffer, text[i])
|
|
}
|
|
}
|
|
return buffer
|
|
}
|
|
|
|
func appendServiceCheck(buffer []byte, serviceCheck ServiceCheck, globalTags []string) []byte {
|
|
buffer = append(buffer, "_sc|"...)
|
|
buffer = append(buffer, serviceCheck.Name...)
|
|
buffer = append(buffer, '|')
|
|
buffer = strconv.AppendInt(buffer, int64(serviceCheck.Status), 10)
|
|
|
|
if !serviceCheck.Timestamp.IsZero() {
|
|
buffer = append(buffer, "|d:"...)
|
|
buffer = strconv.AppendInt(buffer, int64(serviceCheck.Timestamp.Unix()), 10)
|
|
}
|
|
|
|
if len(serviceCheck.Hostname) != 0 {
|
|
buffer = append(buffer, "|h:"...)
|
|
buffer = append(buffer, serviceCheck.Hostname...)
|
|
}
|
|
|
|
buffer = appendTags(buffer, globalTags, serviceCheck.Tags)
|
|
|
|
if len(serviceCheck.Message) != 0 {
|
|
buffer = append(buffer, "|m:"...)
|
|
buffer = appendEscapedServiceCheckText(buffer, serviceCheck.Message)
|
|
}
|
|
return buffer
|
|
}
|
|
|
|
func appendSeparator(buffer []byte) []byte {
|
|
return append(buffer, '\n')
|
|
}
|