func findHandler(w http.ResponseWriter, req *http.Request) { logger.Debugln("request: ", req.URL.RequestURI()) Metrics.FindRequests.Add(1) rewrite, _ := url.ParseRequestURI(req.URL.RequestURI()) v := rewrite.Query() format := req.FormValue("format") v.Set("format", "protobuf") rewrite.RawQuery = v.Encode() query := req.FormValue("query") var tld string if i := strings.IndexByte(query, '.'); i > 0 { tld = query[:i] } // lookup tld in our map of where they live to reduce the set of // servers we bug with our find Config.mu.RLock() var backends []string var ok bool if backends, ok = Config.metricPaths[tld]; !ok || backends == nil || len(backends) == 0 { backends = Config.Backends } Config.mu.RUnlock() responses := multiGet(backends, rewrite.RequestURI()) if responses == nil || len(responses) == 0 { logger.Logln("find: error querying backends for: ", rewrite.RequestURI()) http.Error(w, "find: error querying backends", http.StatusInternalServerError) return } metrics, paths := findHandlerPB(w, req, responses) // update our cache of which servers have which metrics Config.mu.Lock() for k, v := range paths { Config.metricPaths[k] = v } Config.mu.Unlock() switch format { case "protobuf": w.Header().Set("Content-Type", "application/protobuf") var result pb.GlobResponse query := req.FormValue("query") result.Name = &query result.Matches = metrics b, _ := proto.Marshal(&result) w.Write(b) case "json": w.Header().Set("Content-Type", "application/json") jEnc := json.NewEncoder(w) jEnc.Encode(metrics) case "", "pickle": w.Header().Set("Content-Type", "application/pickle") var result []map[string]interface{} for _, metric := range metrics { mm := map[string]interface{}{ "metric_path": *metric.Path, "isLeaf": *metric.IsLeaf, } result = append(result, mm) } pEnc := pickle.NewEncoder(w) pEnc.Encode(result) } }
func findHandler(wr http.ResponseWriter, req *http.Request) { // URL: /metrics/find/?local=1&format=pickle&query=the.metric.path.with.glob t0 := time.Now() Metrics.FindRequests.Add(1) req.ParseForm() format := req.FormValue("format") query := req.FormValue("query") if format != "json" && format != "pickle" && format != "protobuf" { Metrics.FindErrors.Add(1) logger.Logf("dropping invalid uri (format=%s): %s", format, req.URL.RequestURI()) http.Error(wr, "Bad request (unsupported format)", http.StatusBadRequest) return } if query == "" { Metrics.FindErrors.Add(1) logger.Logf("dropping invalid request (query=): %s", req.URL.RequestURI()) http.Error(wr, "Bad request (no query)", http.StatusBadRequest) return } files, leafs := expandGlobs(query) if format == "json" || format == "protobuf" { name := req.FormValue("query") response := pb.GlobResponse{ Name: &name, Matches: make([]*pb.GlobMatch, 0), } for i, p := range files { response.Matches = append(response.Matches, &pb.GlobMatch{Path: proto.String(p), IsLeaf: proto.Bool(leafs[i])}) } var b []byte var err error switch format { case "json": b, err = json.Marshal(response) case "protobuf": b, err = proto.Marshal(&response) } if err != nil { Metrics.FindErrors.Add(1) logger.Logf("failed to create %s data for glob %s: %s", format, *response.Name, err) return } wr.Write(b) } else if format == "pickle" { // [{'metric_path': 'metric', 'intervals': [(x,y)], 'isLeaf': True},] var metrics []map[string]interface{} var m map[string]interface{} for i, p := range files { m = make(map[string]interface{}) m["metric_path"] = p // m["intervals"] = dunno how to do a tuple here m["isLeaf"] = leafs[i] metrics = append(metrics, m) } wr.Header().Set("Content-Type", "application/pickle") pEnc := pickle.NewEncoder(wr) pEnc.Encode(metrics) } if len(files) == 0 { // to get an idea how often we search for nothing Metrics.FindZero.Add(1) } logger.Debugf("find: %d hits for %s in %v", len(files), req.FormValue("query"), time.Since(t0)) return }