// ListenAndServe binds the server to the given UDP interface. func (u *UDPServer) ListenAndServe(iface string) error { addr, err := net.ResolveUDPAddr("udp", iface) if err != nil { log.Printf("Failed resolve UDP address %s: %s", iface, err) return err } conn, err := net.ListenUDP("udp", addr) if err != nil { log.Printf("Failed set up UDP listener at address %s: %s", addr, err) return err } var bp client.BatchPoints buf := make([]byte, udpBufferSize) go func() { for { _, _, err := conn.ReadFromUDP(buf) if err != nil { log.Printf("Failed read UDP message: %s.", err) continue } dec := json.NewDecoder(bytes.NewReader(buf)) if err := dec.Decode(&bp); err != nil { log.Printf("Failed decode JSON UDP message") continue } points, err := influxdb.NormalizeBatchPoints(bp) if err != nil { log.Printf("Failed normalize batch points") continue } if msgIndex, err := u.writer.WriteSeries(bp.Database, bp.RetentionPolicy, points); err != nil { log.Printf("Server write failed. Message index was %d: %s", msgIndex, err) } } }() return nil }
func TestNormalizeBatchPoints(t *testing.T) { now := time.Now() tests := []struct { name string bp client.BatchPoints p []influxdb.Point err string }{ { name: "default", bp: client.BatchPoints{ Points: []client.Point{ {Name: "cpu", Tags: map[string]string{"region": "useast"}, Timestamp: now, Fields: map[string]interface{}{"value": 1.0}}, }, }, p: []influxdb.Point{ {Name: "cpu", Tags: map[string]string{"region": "useast"}, Timestamp: now, Fields: map[string]interface{}{"value": 1.0}}, }, }, { name: "merge timestamp", bp: client.BatchPoints{ Timestamp: now, Points: []client.Point{ {Name: "cpu", Tags: map[string]string{"region": "useast"}, Fields: map[string]interface{}{"value": 1.0}}, }, }, p: []influxdb.Point{ {Name: "cpu", Tags: map[string]string{"region": "useast"}, Timestamp: now, Fields: map[string]interface{}{"value": 1.0}}, }, }, { name: "merge tags", bp: client.BatchPoints{ Tags: map[string]string{"day": "monday"}, Points: []client.Point{ {Name: "cpu", Tags: map[string]string{"region": "useast"}, Timestamp: now, Fields: map[string]interface{}{"value": 1.0}}, {Name: "memory", Timestamp: now, Fields: map[string]interface{}{"value": 2.0}}, }, }, p: []influxdb.Point{ {Name: "cpu", Tags: map[string]string{"day": "monday", "region": "useast"}, Timestamp: now, Fields: map[string]interface{}{"value": 1.0}}, {Name: "memory", Tags: map[string]string{"day": "monday"}, Timestamp: now, Fields: map[string]interface{}{"value": 2.0}}, }, }, } for _, test := range tests { t.Logf("running test %q", test.name) p, e := influxdb.NormalizeBatchPoints(test.bp) if test.err == "" && e != nil { t.Errorf("unexpected error %v", e) } else if test.err != "" && e == nil { t.Errorf("expected error %s, got <nil>", test.err) } else if e != nil && test.err != e.Error() { t.Errorf("unexpected error. expected: %s, got %v", test.err, e) } if !reflect.DeepEqual(p, test.p) { t.Logf("expected: %+v", test.p) t.Logf("got: %+v", p) t.Error("failed to normalize.") } } }
// serveWrite receives incoming series data and writes it to the database. func (h *Handler) serveWrite(w http.ResponseWriter, r *http.Request, user *influxdb.User) { var bp client.BatchPoints var dec *json.Decoder if h.WriteTrace { b, err := ioutil.ReadAll(r.Body) if err != nil { h.Logger.Print("write handler failed to read bytes from request body") } else { h.Logger.Printf("write body received by handler: %s", string(b)) } dec = json.NewDecoder(strings.NewReader(string(b))) } else { dec = json.NewDecoder(r.Body) defer r.Body.Close() } var writeError = func(result influxdb.Result, statusCode int) { w.WriteHeader(statusCode) w.Header().Add("content-type", "application/json") _ = json.NewEncoder(w).Encode(&result) return } if err := dec.Decode(&bp); err != nil { if err.Error() == "EOF" { w.WriteHeader(http.StatusOK) return } writeError(influxdb.Result{Err: err}, http.StatusInternalServerError) return } if bp.Database == "" { writeError(influxdb.Result{Err: fmt.Errorf("database is required")}, http.StatusInternalServerError) return } if !h.server.DatabaseExists(bp.Database) { writeError(influxdb.Result{Err: fmt.Errorf("database not found: %q", bp.Database)}, http.StatusNotFound) return } if h.requireAuthentication && user == nil { writeError(influxdb.Result{Err: fmt.Errorf("user is required to write to database %q", bp.Database)}, http.StatusUnauthorized) return } if h.requireAuthentication && !user.Authorize(influxql.WritePrivilege, bp.Database) { writeError(influxdb.Result{Err: fmt.Errorf("%q user is not authorized to write to database %q", user.Name, bp.Database)}, http.StatusUnauthorized) return } points, err := influxdb.NormalizeBatchPoints(bp) if err != nil { writeError(influxdb.Result{Err: err}, http.StatusInternalServerError) return } if index, err := h.server.WriteSeries(bp.Database, bp.RetentionPolicy, points); err != nil { writeError(influxdb.Result{Err: err}, http.StatusInternalServerError) return } else { w.Header().Add("X-InfluxDB-Index", fmt.Sprintf("%d", index)) } }