| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- package statsd
- import (
- "strconv"
- "strings"
- )
- var (
- gaugeSymbol = []byte("g")
- countSymbol = []byte("c")
- histogramSymbol = []byte("h")
- distributionSymbol = []byte("d")
- setSymbol = []byte("s")
- timingSymbol = []byte("ms")
- tagSeparatorSymbol = ","
- )
- 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, tagSeparatorSymbol...)
- }
- buffer = appendWithoutNewlines(buffer, tag)
- firstTag = false
- }
- for _, tag := range tags {
- if !firstTag {
- buffer = append(buffer, tagSeparatorSymbol...)
- }
- buffer = appendWithoutNewlines(buffer, tag)
- firstTag = false
- }
- return buffer
- }
- func appendTagsAggregated(buffer []byte, globalTags []string, tags string) []byte {
- if len(globalTags) == 0 && tags == "" {
- return buffer
- }
- buffer = append(buffer, "|#"...)
- firstTag := true
- for _, tag := range globalTags {
- if !firstTag {
- buffer = append(buffer, tagSeparatorSymbol...)
- }
- buffer = appendWithoutNewlines(buffer, tag)
- firstTag = false
- }
- if tags != "" {
- if !firstTag {
- buffer = append(buffer, tagSeparatorSymbol...)
- }
- buffer = appendWithoutNewlines(buffer, tags)
- }
- 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, tagSeparatorSymbol...)
- 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')
- }
|