open-nomad/vendor/github.com/DataDog/datadog-go/statsd/format.go
Seth Hoenig 435c0d9fc8 deps: Switch to Go modules for dependency management
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.
2020-06-02 14:30:36 -05:00

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')
}