Closed gfreezy closed 4 years ago
Merging #26 into master will not change coverage. The diff coverage is
100.00%
.
@@ Coverage Diff @@
## master #26 +/- ##
=======================================
Coverage 88.05% 88.05%
=======================================
Files 5 5
Lines 335 335
=======================================
Hits 295 295
Misses 37 37
Partials 3 3
Impacted Files | Coverage Δ | |
---|---|---|
tags.go | 100.00% <100.00%> (ø) |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update 448e76c...507b11d. Read the comment docs.
I feel these fields are internal details of the implementation.
The only way to create a tag is via public functions, can you validate before creating a tag?
Currently i am doing like this, copy Tag
related code to my own repo. This looks a bit verbose.
Wish there is a better way than duplicating the code from go-statsd
.
package metrics
import (
"github.com/devopsfaith/krakend/config"
"github.com/devopsfaith/krakend/logging"
"github.com/mitchellh/mapstructure"
"github.com/smira/go-statsd"
"os"
"strings"
"time"
)
const Namespace = "github_com/xiachufang/krakend-ce/pkg/metrics"
const (
typeString = iota
typeInt64
)
// Tag is metric-specific tag
type Tag struct {
name string
strvalue string
intvalue int64
typ byte
}
type Metrics struct {
statsdClient *statsd.Client
}
type metricsConfig struct {
Address string
Prefix string
}
func NewMetrics(config config.ExtraConfig, l logging.Logger) *Metrics {
raw := config[Namespace]
var metricsConfig metricsConfig
err := mapstructure.Decode(raw, &metricsConfig)
if err != nil {
return &Metrics{
statsdClient: nil,
}
}
hostname, err := os.Hostname()
if err != nil {
l.Warning("get hostname error")
hostname = "unknown"
}
return &Metrics{
statsdClient: statsd.NewClient(metricsConfig.Address, func(options *statsd.ClientOptions) {
options.DefaultTags = []statsd.Tag{statsd.StringTag("server", hostname)}
if !strings.HasSuffix(metricsConfig.Prefix, ".") {
metricsConfig.Prefix += "."
}
options.MetricPrefix = metricsConfig.Prefix
options.FlushInterval = time.Second
options.ReconnectInterval = 5 * time.Minute
}),
}
}
func (metrics *Metrics) Incr(name string, value int64, tags ...Tag) {
if metrics.statsdClient != nil {
metrics.statsdClient.Incr(name, value, sanitizeTags(tags)...)
}
}
func (metrics *Metrics) Decr(name string, value int64, tags ...Tag) {
if metrics.statsdClient != nil {
metrics.statsdClient.Incr(name, value, sanitizeTags(tags)...)
}
}
func (metrics *Metrics) Gauge(name string, value int64, tags ...Tag) {
if metrics.statsdClient != nil {
metrics.statsdClient.Gauge(name, value, sanitizeTags(tags)...)
}
}
func (metrics *Metrics) Timing(name string, value int64, tags ...Tag) {
if metrics.statsdClient != nil {
metrics.statsdClient.Timing(name, value, sanitizeTags(tags)...)
}
}
func (metrics *Metrics) PrecisionTiming(name string, value time.Duration, tags ...Tag) {
if metrics.statsdClient != nil {
metrics.statsdClient.PrecisionTiming(name, value, sanitizeTags(tags)...)
}
}
// StringTag creates Tag with string value
func StringTag(name, value string) Tag {
return Tag{name: name, strvalue: value, typ: typeString}
}
// IntTag creates Tag with integer value
func IntTag(name string, value int) Tag {
return Tag{name: name, intvalue: int64(value), typ: typeInt64}
}
// Int64Tag creates Tag with integer value
func Int64Tag(name string, value int64) Tag {
return Tag{name: name, intvalue: value, typ: typeInt64}
}
func sanitizeTags(tags []Tag) []statsd.Tag {
var sanitizedTags []statsd.Tag
for _, tag := range tags {
if tag.typ == typeInt64 {
sanitizedTags = append(sanitizedTags, statsd.Int64Tag(sanitizeValue(tag.name), tag.intvalue))
} else if tag.typ == typeString {
sanitizedTags = append(sanitizedTags, statsd.StringTag(sanitizeValue(tag.name), sanitizeValue(tag.strvalue)))
}
}
return sanitizedTags
}
func sanitizeValue(v string) string {
v = strings.ReplaceAll(v, ":", "_")
v = strings.ReplaceAll(v, ",", "_")
v = strings.ReplaceAll(v, " ", "_")
v = strings.ReplaceAll(v, "\"", "'")
v = strings.ReplaceAll(v, "=", "_")
return v
}
can you then just provide your own implementations of StringTag
(and IntTag
, ..), which does sanitizeValue
, return your own type Tag
which you will typecast back to statsd.Tag
before sending it to Incr
and other funcs?
what you're doing is just wrapping statsd
library with another layer of extra sanitization/features
got it.
Export
Tag
fields.:
,
=
"
are not valid characters in statsd line protocol. I need to remove these characters before sending togo-statsd
client.closed #25