func BenchmarkParsePointWithPrecisionU(b *testing.B) { line := `cpu value=1i 1000000000` defaultTime := time.Now().UTC() for i := 0; i < b.N; i++ { models.ParsePointsWithPrecision([]byte(line), defaultTime, "u") b.SetBytes(int64(len(line))) } }
func (r *replayStreamSource) replayStream(stream StreamCollector, recTime bool, precision string) { defer stream.Close() defer r.data.Close() start := time.Time{} var diff time.Duration zero := r.clck.Zero() for r.in.Scan() { db := r.in.Text() if !r.in.Scan() { r.err <- fmt.Errorf("invalid replay file format, expected another line") return } rp := r.in.Text() if !r.in.Scan() { r.err <- fmt.Errorf("invalid replay file format, expected another line") return } points, err := dbmodels.ParsePointsWithPrecision( r.in.Bytes(), zero, precision, ) if err != nil { r.err <- err return } if start.IsZero() { start = points[0].Time() diff = zero.Sub(start) } var t time.Time waitTime := points[0].Time().Add(diff).UTC() if !recTime { t = waitTime } else { t = points[0].Time().UTC() } mp := points[0] p := models.Point{ Database: db, RetentionPolicy: rp, Name: mp.Name(), Group: models.NilGroup, Tags: models.Tags(mp.Tags()), Fields: models.Fields(mp.Fields()), Time: t, } r.clck.Until(waitTime) err = stream.CollectPoint(p) if err != nil { r.err <- err return } } r.err <- r.in.Err() }
func TestParsePointsWithPrecisionComments(t *testing.T) { tests := []struct { name string batch string exp string lenPoints int }{ { name: "comment only", batch: `# comment only`, exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", lenPoints: 0, }, { name: "point with comment above", batch: `# a point is below cpu,host=serverA,region=us-east value=1.0 946730096789012345`, exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", lenPoints: 1, }, { name: "point with comment below", batch: `cpu,host=serverA,region=us-east value=1.0 946730096789012345 # end of points`, exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", lenPoints: 1, }, { name: "indented comment", batch: ` # a point is below cpu,host=serverA,region=us-east value=1.0 946730096789012345`, exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", lenPoints: 1, }, } for _, test := range tests { pts, err := models.ParsePointsWithPrecision([]byte(test.batch), time.Now().UTC(), "") if err != nil { t.Fatalf(`%s: ParsePoints() failed. got %s`, test.name, err) } pointsLength := len(pts) if exp := test.lenPoints; pointsLength != exp { t.Errorf("%s: ParsePoint() len mismatch: got %v, exp %v", test.name, pointsLength, exp) } if pointsLength > 0 { pt := pts[0] got := pt.String() if got != test.exp { t.Errorf("%s: ParsePoint() to string mismatch:\n got %v\n exp %v", test.name, got, test.exp) } } } }
func test(t *testing.T, line string, point models.Point) { pts, err := models.ParsePointsWithPrecision([]byte(line), time.Unix(0, 0), "n") if err != nil { t.Fatalf(`ParsePoints("%s") mismatch. got %v, exp nil`, line, err) } if exp := 1; len(pts) != exp { t.Fatalf(`ParsePoints("%s") len mismatch. got %d, exp %d`, line, len(pts), exp) } if exp := point.Key(); !bytes.Equal(pts[0].Key(), exp) { t.Errorf("ParsePoints(\"%s\") key mismatch.\ngot %v\nexp %v", line, string(pts[0].Key()), string(exp)) } if exp := len(point.Tags()); len(pts[0].Tags()) != exp { t.Errorf(`ParsePoints("%s") tags mismatch. got %v, exp %v`, line, pts[0].Tags(), exp) } for tag, value := range point.Tags() { if pts[0].Tags()[tag] != value { t.Errorf(`ParsePoints("%s") tags mismatch. got %v, exp %v`, line, pts[0].Tags()[tag], value) } } for name, value := range point.Fields() { val := pts[0].Fields()[name] expfval, ok := val.(float64) if ok && math.IsNaN(expfval) { gotfval, ok := value.(float64) if ok && !math.IsNaN(gotfval) { t.Errorf(`ParsePoints("%s") field '%s' mismatch. exp NaN`, line, name) } } else if !reflect.DeepEqual(pts[0].Fields()[name], value) { t.Errorf(`ParsePoints("%s") field '%s' mismatch. got %v, exp %v`, line, name, pts[0].Fields()[name], value) } } if !pts[0].Time().Equal(point.Time()) { t.Errorf(`ParsePoints("%s") time mismatch. got %v, exp %v`, line, pts[0].Time(), point.Time()) } if !strings.HasPrefix(pts[0].String(), line) { t.Errorf("ParsePoints string mismatch.\ngot: %v\nexp: %v", pts[0].String(), line) } }
func (s *Service) parser() { defer s.wg.Done() for { select { case <-s.done: return case buf := <-s.parserChan: points, err := models.ParsePointsWithPrecision(buf, time.Now().UTC(), s.config.Precision) if err != nil { s.statMap.Add(statPointsParseFail, 1) s.Logger.Printf("Failed to parse points: %s", err) continue } for _, point := range points { s.batcher.In() <- point } s.statMap.Add(statPointsReceived, int64(len(points))) } } }
// serveWriteLine receives incoming series data in line protocol format and writes it to the database. func (h *Handler) serveWriteLine(w http.ResponseWriter, r *http.Request, body []byte, user *meta.UserInfo) { // Some clients may not set the content-type header appropriately and send JSON with a non-json // content-type. If the body looks JSON, try to handle it as as JSON instead if len(body) > 0 { var i int for { // JSON requests must start w/ an opening bracket if body[i] == '{' { h.serveWriteJSON(w, r, body, user) return } // check that the byte is in the standard ascii code range if body[i] > 32 || i >= len(body)-1 { break } i++ } } precision := r.FormValue("precision") if precision == "" { precision = "n" } points, parseError := models.ParsePointsWithPrecision(body, time.Now().UTC(), precision) // Not points parsed correctly so return the error now if parseError != nil && len(points) == 0 { if parseError.Error() == "EOF" { w.WriteHeader(http.StatusOK) return } resultError(w, influxql.Result{Err: parseError}, http.StatusBadRequest) return } database := r.FormValue("db") if database == "" { resultError(w, influxql.Result{Err: fmt.Errorf("database is required")}, http.StatusBadRequest) return } if di, err := h.MetaClient.Database(database); err != nil { resultError(w, influxql.Result{Err: fmt.Errorf("metastore database error: %s", err)}, http.StatusInternalServerError) return } else if di == nil { resultError(w, influxql.Result{Err: fmt.Errorf("database not found: %q", database)}, http.StatusNotFound) return } if h.requireAuthentication && user == nil { resultError(w, influxql.Result{Err: fmt.Errorf("user is required to write to database %q", database)}, http.StatusUnauthorized) return } if h.requireAuthentication && !user.Authorize(influxql.WritePrivilege, database) { resultError(w, influxql.Result{Err: fmt.Errorf("%q user is not authorized to write to database %q", user.Name, database)}, http.StatusUnauthorized) return } // Determine required consistency level. consistency := cluster.ConsistencyLevelOne switch r.Form.Get("consistency") { case "all": consistency = cluster.ConsistencyLevelAll case "any": consistency = cluster.ConsistencyLevelAny case "one": consistency = cluster.ConsistencyLevelOne case "quorum": consistency = cluster.ConsistencyLevelQuorum } // Write points. if err := h.PointsWriter.WritePoints(&cluster.WritePointsRequest{ Database: database, RetentionPolicy: r.FormValue("rp"), ConsistencyLevel: consistency, Points: points, }); influxdb.IsClientError(err) { h.statMap.Add(statPointsWrittenFail, int64(len(points))) resultError(w, influxql.Result{Err: err}, http.StatusBadRequest) return } else if err != nil { h.statMap.Add(statPointsWrittenFail, int64(len(points))) resultError(w, influxql.Result{Err: err}, http.StatusInternalServerError) return } else if parseError != nil { // We wrote some of the points h.statMap.Add(statPointsWrittenOK, int64(len(points))) // The other points failed to parse which means the client sent invalid line protocol. We return a 400 // response code as well as the lines that failed to parse. resultError(w, influxql.Result{Err: fmt.Errorf("partial write:\n%v", parseError)}, http.StatusBadRequest) return } h.statMap.Add(statPointsWrittenOK, int64(len(points))) w.WriteHeader(http.StatusNoContent) }
func TestParsePointsWithPrecisionNoTime(t *testing.T) { line := `cpu,host=serverA,region=us-east value=1.0` tm, _ := time.Parse(time.RFC3339Nano, "2000-01-01T12:34:56.789012345Z") tests := []struct { name string precision string exp string }{ { name: "no precision", precision: "", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", }, { name: "nanosecond precision", precision: "n", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", }, { name: "microsecond precision", precision: "u", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012000", }, { name: "millisecond precision", precision: "ms", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789000000", }, { name: "second precision", precision: "s", exp: "cpu,host=serverA,region=us-east value=1.0 946730096000000000", }, { name: "minute precision", precision: "m", exp: "cpu,host=serverA,region=us-east value=1.0 946730040000000000", }, { name: "hour precision", precision: "h", exp: "cpu,host=serverA,region=us-east value=1.0 946728000000000000", }, } for _, test := range tests { pts, err := models.ParsePointsWithPrecision([]byte(line), tm, test.precision) if err != nil { t.Fatalf(`%s: ParsePoints() failed. got %s`, test.name, err) } if exp := 1; len(pts) != exp { t.Errorf("%s: ParsePoint() len mismatch: got %v, exp %v", test.name, len(pts), exp) } pt := pts[0] got := pt.String() if got != test.exp { t.Errorf("%s: ParsePoint() to string mismatch:\n got %v\n exp %v", test.name, got, test.exp) } } }
func TestParsePointsWithPrecision(t *testing.T) { tests := []struct { name string line string precision string exp string }{ { name: "nanosecond by default", line: `cpu,host=serverA,region=us-east value=1.0 946730096789012345`, precision: "", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", }, { name: "nanosecond", line: `cpu,host=serverA,region=us-east value=1.0 946730096789012345`, precision: "n", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345", }, { name: "microsecond", line: `cpu,host=serverA,region=us-east value=1.0 946730096789012`, precision: "u", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012000", }, { name: "millisecond", line: `cpu,host=serverA,region=us-east value=1.0 946730096789`, precision: "ms", exp: "cpu,host=serverA,region=us-east value=1.0 946730096789000000", }, { name: "second", line: `cpu,host=serverA,region=us-east value=1.0 946730096`, precision: "s", exp: "cpu,host=serverA,region=us-east value=1.0 946730096000000000", }, { name: "minute", line: `cpu,host=serverA,region=us-east value=1.0 15778834`, precision: "m", exp: "cpu,host=serverA,region=us-east value=1.0 946730040000000000", }, { name: "hour", line: `cpu,host=serverA,region=us-east value=1.0 262980`, precision: "h", exp: "cpu,host=serverA,region=us-east value=1.0 946728000000000000", }, } for _, test := range tests { pts, err := models.ParsePointsWithPrecision([]byte(test.line), time.Now().UTC(), test.precision) if err != nil { t.Fatalf(`%s: ParsePoints() failed. got %s`, test.name, err) } if exp := 1; len(pts) != exp { t.Errorf("%s: ParsePoint() len mismatch: got %v, exp %v", test.name, len(pts), exp) } pt := pts[0] got := pt.String() if got != test.exp { t.Errorf("%s: ParsePoint() to string mismatch:\n got %v\n exp %v", test.name, got, test.exp) } } }
// Ensure points can be written to the engine and queried in reverse order. func TestEngine_WritePoints_Reverse(t *testing.T) { e := OpenDefaultEngine() defer e.Close() // Create metadata. mf := &tsdb.MeasurementFields{Fields: make(map[string]*tsdb.Field)} mf.CreateFieldIfNotExists("value", influxql.Float) seriesToCreate := []*tsdb.SeriesCreate{ {Series: tsdb.NewSeries(string(models.MakeKey([]byte("temperature"), nil)), nil)}, } // Parse point. points, err := models.ParsePointsWithPrecision([]byte("temperature value=100 0"), time.Now().UTC(), "s") if err != nil { t.Fatal(err) } else if data, err := mf.Codec.EncodeFields(points[0].Fields()); err != nil { t.Fatal(err) } else { points[0].SetData(data) } // Write original value. if err := e.WritePoints(points, map[string]*tsdb.MeasurementFields{"temperature": mf}, seriesToCreate); err != nil { t.Fatal(err) } // Flush to disk. if err := e.Flush(0); err != nil { t.Fatal(err) } // Parse new point. points, err = models.ParsePointsWithPrecision([]byte("temperature value=200 1"), time.Now().UTC(), "s") if err != nil { t.Fatal(err) } else if data, err := mf.Codec.EncodeFields(points[0].Fields()); err != nil { t.Fatal(err) } else { points[0].SetData(data) } // Write the new points existing value. if err := e.WritePoints(points, nil, nil); err != nil { t.Fatal(err) } // Ensure only the updated value is read. tx := e.MustBegin(false) defer tx.Rollback() c := tx.Cursor("temperature", []string{"value"}, mf.Codec, false) if k, _ := c.SeekTo(math.MaxInt64); k != time.Unix(1, 0).UnixNano() { t.Fatalf("unexpected key: %v", k) } else if k, v := c.Next(); k != time.Unix(0, 0).UnixNano() { t.Fatalf("unexpected key: %v", k) } else if v == nil || v.(float64) != 100 { t.Errorf("unexpected value: %#v", v) } if k, v := c.Next(); k != tsdb.EOF { t.Fatalf("unexpected key/value: %#v / %#v", k, v) } }
// Ensure points can be written to the engine and queried. func TestEngine_WritePoints(t *testing.T) { e := OpenDefaultEngine() defer e.Close() // Create metadata. mf := &tsdb.MeasurementFields{Fields: make(map[string]*tsdb.Field)} mf.CreateFieldIfNotExists("value", influxql.Float) seriesToCreate := []*tsdb.SeriesCreate{ {Series: tsdb.NewSeries(string(models.MakeKey([]byte("temperature"), nil)), nil)}, } // Parse point. points, err := models.ParsePointsWithPrecision([]byte("temperature value=100 1434059627"), time.Now().UTC(), "s") if err != nil { t.Fatal(err) } else if data, err := mf.Codec.EncodeFields(points[0].Fields()); err != nil { t.Fatal(err) } else { points[0].SetData(data) } // Write original value. if err := e.WritePoints(points, map[string]*tsdb.MeasurementFields{"temperature": mf}, seriesToCreate); err != nil { t.Fatal(err) } // Flush to disk. if err := e.Flush(0); err != nil { t.Fatal(err) } // Parse new point. points, err = models.ParsePointsWithPrecision([]byte("temperature value=200 1434059627"), time.Now().UTC(), "s") if err != nil { t.Fatal(err) } else if data, err := mf.Codec.EncodeFields(points[0].Fields()); err != nil { t.Fatal(err) } else { points[0].SetData(data) } // Update existing value. if err := e.WritePoints(points, nil, nil); err != nil { t.Fatal(err) } // Ensure only the updated value is read. tx := e.MustBegin(false) defer tx.Rollback() c := tx.Cursor("temperature", tsdb.Forward) if k, v := c.Seek([]byte{0}); !bytes.Equal(k, u64tob(uint64(time.Unix(1434059627, 0).UnixNano()))) { t.Fatalf("unexpected key: %#v", k) } else if m, err := mf.Codec.DecodeFieldsWithNames(v); err != nil { t.Fatal(err) } else if m["value"] != float64(200) { t.Errorf("unexpected value: %#v", m) } if k, v := c.Next(); k != nil { t.Fatalf("unexpected key/value: %#v / %#v", k, v) } }
// serveWriteLine receives incoming series data in line protocol format and writes it to the database. func (h *Handler) serveWriteLine(w http.ResponseWriter, r *http.Request, body []byte, user *meta.UserInfo) { precision := r.FormValue("precision") if precision == "" { precision = "n" } points, err := models.ParsePointsWithPrecision(body, time.Now().UTC(), precision) if err != nil { if err.Error() == "EOF" { w.WriteHeader(http.StatusOK) return } h.writeError(w, influxql.Result{Err: err}, http.StatusBadRequest) return } database := r.FormValue("db") if database == "" { h.writeError(w, influxql.Result{Err: fmt.Errorf("database is required")}, http.StatusBadRequest) return } if di, err := h.MetaClient.Database(database); err != nil { h.writeError(w, influxql.Result{Err: fmt.Errorf("metastore database error: %s", err)}, http.StatusInternalServerError) return } else if di == nil { h.writeError(w, influxql.Result{Err: fmt.Errorf("database not found: %q", database)}, http.StatusNotFound) return } if h.requireAuthentication && user == nil { h.writeError(w, influxql.Result{Err: fmt.Errorf("user is required to write to database %q", database)}, http.StatusUnauthorized) return } if h.requireAuthentication && !user.Authorize(influxql.WritePrivilege, database) { h.writeError(w, influxql.Result{Err: fmt.Errorf("%q user is not authorized to write to database %q", user.Name, database)}, http.StatusUnauthorized) return } // Determine required consistency level. consistency := cluster.ConsistencyLevelOne switch r.Form.Get("consistency") { case "all": consistency = cluster.ConsistencyLevelAll case "any": consistency = cluster.ConsistencyLevelAny case "one": consistency = cluster.ConsistencyLevelOne case "quorum": consistency = cluster.ConsistencyLevelQuorum } // Write points. if err := h.PointsWriter.WritePoints(&cluster.WritePointsRequest{ Database: database, RetentionPolicy: r.FormValue("rp"), ConsistencyLevel: consistency, Points: points, }); influxdb.IsClientError(err) { h.statMap.Add(statPointsWrittenFail, int64(len(points))) h.writeError(w, influxql.Result{Err: err}, http.StatusBadRequest) return } else if err != nil { h.statMap.Add(statPointsWrittenFail, int64(len(points))) h.writeError(w, influxql.Result{Err: err}, http.StatusInternalServerError) return } h.statMap.Add(statPointsWrittenOK, int64(len(points))) w.WriteHeader(http.StatusNoContent) }
func TestStream_InfluxDBOut(t *testing.T) { var script = ` stream .from().measurement('cpu') .where(lambda: "host" == 'serverA') .window() .period(10s) .every(10s) .mapReduce(influxql.count('value')) .influxDBOut() .database('db') .retentionPolicy('rp') .measurement('m') .precision('s') .tag('key', 'value') ` done := make(chan error, 1) var points []imodels.Point var database string var rp string var precision string influxdb := NewMockInfluxDBService(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { //Respond var data client.Response w.WriteHeader(http.StatusOK) _ = json.NewEncoder(w).Encode(data) //Get request data database = r.URL.Query().Get("db") rp = r.URL.Query().Get("rp") precision = r.URL.Query().Get("precision") b, err := ioutil.ReadAll(r.Body) if err != nil { done <- err return } points, err = imodels.ParsePointsWithPrecision(b, time.Unix(0, 0), precision) done <- err })) clock, et, replayErr, tm := testStreamer(t, "TestStream_InfluxDBOut", script) tm.InfluxDBService = influxdb defer tm.Close() err := fastForwardTask(clock, et, replayErr, tm, 15*time.Second) if err != nil { t.Error(err) } // Wait till we received a request if e := <-done; e != nil { t.Error(e) } if database != "db" { t.Errorf("got %v exp %v", database, "db") } if rp != "rp" { t.Errorf("got %v exp %v", rp, "rp") } if precision != "s" { t.Errorf("got %v exp %v", precision, "s") } if 1 != len(points) { t.Errorf("got %v exp %v", len(points), 1) } else { p := points[0] if p.Name() != "m" { t.Errorf("got %v exp %v", p.Name(), "m") } if p.Fields()["count"] != 10.0 { t.Errorf("got %v exp %v", p.Fields()["count"], 10.0) } if len(p.Tags()) != 1 { t.Errorf("got %v exp %v", len(p.Tags()), 1) } if p.Tags()["key"] != "value" { t.Errorf("got %s exp %s", p.Tags()["key"], "value") } tm := time.Date(1971, 1, 1, 0, 0, 10, 0, time.UTC) if !tm.Equal(p.Time()) { t.Errorf("times are not equal exp %s got %s", tm, p.Time()) } } }