// serveWriteJSON receives incoming series data in JSON and writes it to the database. func (h *Handler) serveWriteJSON(w http.ResponseWriter, r *http.Request, body []byte, user *meta.UserInfo) { var bp client.BatchPoints var dec *json.Decoder dec = json.NewDecoder(bytes.NewReader(body)) if err := dec.Decode(&bp); err != nil { if err.Error() == "EOF" { w.WriteHeader(http.StatusOK) return } resultError(w, influxql.Result{Err: err}, http.StatusBadRequest) return } if bp.Database == "" { resultError(w, influxql.Result{Err: fmt.Errorf("database is required")}, http.StatusBadRequest) return } if di, err := h.MetaStore.Database(bp.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", bp.Database)}, http.StatusNotFound) return } if h.requireAuthentication && user == nil { resultError(w, influxql.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) { resultError(w, influxql.Result{Err: fmt.Errorf("%q user is not authorized to write to database %q", user.Name, bp.Database)}, http.StatusUnauthorized) return } points, err := NormalizeBatchPoints(bp) if err != nil { resultError(w, influxql.Result{Err: err}, http.StatusBadRequest) return } // Convert the json batch struct to a points writer struct if err := h.PointsWriter.WritePoints(&cluster.WritePointsRequest{ Database: bp.Database, RetentionPolicy: bp.RetentionPolicy, ConsistencyLevel: cluster.ConsistencyLevelOne, Points: points, }); influxdb.IsClientError(err) { resultError(w, influxql.Result{Err: err}, http.StatusBadRequest) return } else if err != nil { resultError(w, influxql.Result{Err: err}, http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }
// 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) }
// 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 { break } i += 1 } } precision := r.FormValue("precision") if precision == "" { precision = "n" } points, err := tsdb.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.MetaStore.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.writeError(w, influxql.Result{Err: err}, http.StatusBadRequest) return } else if err != nil { h.writeError(w, influxql.Result{Err: err}, http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }
// ServeHTTP implements OpenTSDB's HTTP /api/put endpoint func (h *Handler) servePut(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() // Require POST method. if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Wrap reader if it's gzip encoded. var br *bufio.Reader if r.Header.Get("Content-Encoding") == "gzip" { zr, err := gzip.NewReader(r.Body) if err != nil { http.Error(w, "could not read gzip, "+err.Error(), http.StatusBadRequest) return } br = bufio.NewReader(zr) } else { br = bufio.NewReader(r.Body) } // Lookahead at the first byte. f, err := br.Peek(1) if err != nil || len(f) != 1 { http.Error(w, "peek error: "+err.Error(), http.StatusBadRequest) return } // Peek to see if this is a JSON array. var multi bool switch f[0] { case '{': case '[': multi = true default: http.Error(w, "expected JSON array or hash", http.StatusBadRequest) return } // Decode JSON data into slice of points. dps := make([]point, 1) if dec := json.NewDecoder(br); multi { if err = dec.Decode(&dps); err != nil { http.Error(w, "json array decode error", http.StatusBadRequest) return } } else { if err = dec.Decode(&dps[0]); err != nil { http.Error(w, "json object decode error", http.StatusBadRequest) return } } // Convert points into TSDB points. points := make([]tsdb.Point, 0, len(dps)) for i := range dps { p := dps[i] // Convert timestamp to Go time. // If time value is over a billion then it's microseconds. var ts time.Time if p.Time < 10000000000 { ts = time.Unix(p.Time, 0) } else { ts = time.Unix(p.Time/1000, (p.Time%1000)*1000) } points = append(points, tsdb.NewPoint(p.Metric, p.Tags, map[string]interface{}{"value": p.Value}, ts)) } // Write points. if err := h.PointsWriter.WritePoints(&cluster.WritePointsRequest{ Database: h.Database, RetentionPolicy: h.RetentionPolicy, ConsistencyLevel: h.ConsistencyLevel, Points: points, }); influxdb.IsClientError(err) { h.Logger.Println("write series error: ", err) http.Error(w, "write series error: "+err.Error(), http.StatusBadRequest) return } else if err != nil { h.Logger.Println("write series error: ", err) http.Error(w, "write series error: "+err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }
// 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) }