consul/vendor/github.com/DataDog/datadog-go/statsd/format.go

233 lines
7.0 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')
}