Fix precision truncation when no timestamp included (#3961)

This commit is contained in:
Daniel Nelson 2018-04-02 14:32:33 -07:00 committed by GitHub
parent 45e77b3301
commit 52d9a98b09
5 changed files with 97 additions and 11 deletions

View File

@ -10,13 +10,15 @@ type TimeFunc func() time.Time
type Builder struct { type Builder struct {
TimeFunc TimeFunc
TimePrecision time.Duration
*metric *metric
} }
func NewBuilder() *Builder { func NewBuilder() *Builder {
b := &Builder{ b := &Builder{
TimeFunc: time.Now, TimeFunc: time.Now,
TimePrecision: 1 * time.Nanosecond,
} }
b.Reset() b.Reset()
return b return b
@ -44,7 +46,7 @@ func (b *Builder) Reset() {
func (b *Builder) Metric() (telegraf.Metric, error) { func (b *Builder) Metric() (telegraf.Metric, error) {
if b.tm.IsZero() { if b.tm.IsZero() {
b.tm = b.TimeFunc() b.tm = b.TimeFunc().Truncate(b.TimePrecision)
} }
return b.metric, nil return b.metric, nil

View File

@ -33,6 +33,8 @@ const (
DEFAULT_MAX_LINE_SIZE = 64 * 1024 DEFAULT_MAX_LINE_SIZE = 64 * 1024
) )
type TimeFunc func() time.Time
type HTTPListener struct { type HTTPListener struct {
ServiceAddress string ServiceAddress string
ReadTimeout internal.Duration ReadTimeout internal.Duration
@ -48,6 +50,8 @@ type HTTPListener struct {
BasicUsername string BasicUsername string
BasicPassword string BasicPassword string
TimeFunc
mu sync.Mutex mu sync.Mutex
wg sync.WaitGroup wg sync.WaitGroup
@ -241,7 +245,7 @@ func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
tooLarge(res) tooLarge(res)
return return
} }
now := time.Now() now := h.TimeFunc()
precision := req.URL.Query().Get("precision") precision := req.URL.Query().Get("precision")
@ -340,7 +344,8 @@ func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
} }
func (h *HTTPListener) parse(b []byte, t time.Time, precision string) error { func (h *HTTPListener) parse(b []byte, t time.Time, precision string) error {
h.handler.SetPrecision(getPrecisionMultiplier(precision)) h.handler.SetTimePrecision(getPrecisionMultiplier(precision))
h.handler.SetTimeFunc(func() time.Time { return t })
metrics, err := h.parser.Parse(b) metrics, err := h.parser.Parse(b)
if err != nil { if err != nil {
return err return err
@ -437,6 +442,7 @@ func init() {
inputs.Add("http_listener", func() telegraf.Input { inputs.Add("http_listener", func() telegraf.Input {
return &HTTPListener{ return &HTTPListener{
ServiceAddress: ":8186", ServiceAddress: ":8186",
TimeFunc: time.Now,
} }
}) })
} }

File diff suppressed because one or more lines are too long

View File

@ -26,8 +26,9 @@ func (h *MetricHandler) SetTimeFunc(f metric.TimeFunc) {
h.builder.TimeFunc = f h.builder.TimeFunc = f
} }
func (h *MetricHandler) SetPrecision(factor time.Duration) { func (h *MetricHandler) SetTimePrecision(precision time.Duration) {
h.precision = factor h.builder.TimePrecision = precision
h.precision = precision
} }
func (h *MetricHandler) Metric() (telegraf.Metric, error) { func (h *MetricHandler) Metric() (telegraf.Metric, error) {

View File

@ -21,10 +21,12 @@ var DefaultTime = func() time.Time {
} }
var ptests = []struct { var ptests = []struct {
name string name string
input []byte input []byte
metrics []telegraf.Metric timeFunc func() time.Time
err error precision time.Duration
metrics []telegraf.Metric
err error
}{ }{
{ {
name: "minimal", name: "minimal",
@ -406,7 +408,7 @@ var ptests = []struct {
err: nil, err: nil,
}, },
{ {
name: "default timestamp", name: "no timestamp",
input: []byte("cpu value=42"), input: []byte("cpu value=42"),
metrics: []telegraf.Metric{ metrics: []telegraf.Metric{
Metric( Metric(
@ -422,6 +424,47 @@ var ptests = []struct {
}, },
err: nil, err: nil,
}, },
{
name: "no timestamp full precision",
input: []byte("cpu value=42"),
timeFunc: func() time.Time {
return time.Unix(42, 123456789)
},
metrics: []telegraf.Metric{
Metric(
metric.New(
"cpu",
map[string]string{},
map[string]interface{}{
"value": 42.0,
},
time.Unix(42, 123456789),
),
),
},
err: nil,
},
{
name: "no timestamp partial precision",
input: []byte("cpu value=42"),
timeFunc: func() time.Time {
return time.Unix(42, 123456789)
},
precision: 1 * time.Millisecond,
metrics: []telegraf.Metric{
Metric(
metric.New(
"cpu",
map[string]string{},
map[string]interface{}{
"value": 42.0,
},
time.Unix(42, 123000000),
),
),
},
err: nil,
},
{ {
name: "multiple lines", name: "multiple lines",
input: []byte("cpu value=42\ncpu value=42"), input: []byte("cpu value=42\ncpu value=42"),
@ -538,6 +581,12 @@ func TestParser(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
handler := NewMetricHandler() handler := NewMetricHandler()
handler.SetTimeFunc(DefaultTime) handler.SetTimeFunc(DefaultTime)
if tt.timeFunc != nil {
handler.SetTimeFunc(tt.timeFunc)
}
if tt.precision > 0 {
handler.SetTimePrecision(tt.precision)
}
parser := NewParser(handler) parser := NewParser(handler)
metrics, err := parser.Parse(tt.input) metrics, err := parser.Parse(tt.input)