func streamqueryzHandler(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return } rows := SqlQueryRpcService.qe.streamQList.GetQueryzRows() if err := r.ParseForm(); err != nil { http.Error(w, fmt.Sprintf("cannot parse form: %s", err), http.StatusInternalServerError) return } format := r.FormValue("format") if format == "json" { js, err := json.Marshal(rows) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(js) return } startHTMLTable(w) defer endHTMLTable(w) w.Write(streamqueryzHeader) for i := range rows { streamqueryzTmpl.Execute(w, rows[i]) } }
// ServeLogs registers the URL on which messages will be broadcast. // It is safe to register multiple URLs for the same StreamLogger. func (logger *StreamLogger) ServeLogs(url string, messageFmt func(url.Values, interface{}) string) { http.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return } if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) } ch := logger.Subscribe("ServeLogs") defer logger.Unsubscribe(ch) // Notify client that we're set up. Helpful to distinguish low-traffic streams from connection issues. w.WriteHeader(http.StatusOK) w.(http.Flusher).Flush() for message := range ch { if _, err := io.WriteString(w, messageFmt(r.Form, message)); err != nil { return } w.(http.Flusher).Flush() } }) log.Infof("Streaming logs from %s at %v.", logger.Name(), url) }
func (cp *CachePool) ServeHTTP(response http.ResponseWriter, request *http.Request) { if err := acl.CheckAccessHTTP(request, acl.MONITORING); err != nil { acl.SendError(response, err) return } defer func() { if x := recover(); x != nil { response.Write(([]byte)(x.(error).Error())) } }() response.Header().Set("Content-Type", "text/plain") pool := cp.getPool() if pool == nil { response.Write(([]byte)("closed")) return } command := request.URL.Path[len(statsURL):] if command == "stats" { command = "" } conn := cp.Get(0) // This is not the same as defer rc.cachePool.Put(conn) defer func() { cp.Put(conn) }() r, err := conn.Stats(command) if err != nil { conn.Close() conn = nil response.Write(([]byte)(err.Error())) } else { response.Write(r) } }
// schemazHandler displays the schema read by the query service. func schemazHandler(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return } startHTMLTable(w) defer endHTMLTable(w) w.Write(schemazHeader) tables := SqlQueryRpcService.qe.schemaInfo.GetSchema() sorter := schemazSorter{ rows: tables, less: func(row1, row2 *schema.Table) bool { return row1.Name > row2.Name }, } sort.Sort(&sorter) envelope := struct { ColumnCategory []string CacheType []string Table *schema.Table }{ ColumnCategory: []string{"other", "number", "varbinary"}, CacheType: []string{"none", "read-write", "write-only"}, } for _, Value := range sorter.rows { envelope.Table = Value schemazTmpl.Execute(w, envelope) } }
func (plr *Planner) ServeHTTP(response http.ResponseWriter, request *http.Request) { if err := acl.CheckAccessHTTP(request, acl.DEBUGGING); err != nil { acl.SendError(response, err) return } if request.URL.Path == "/debug/query_plans" { keys := plr.plans.Keys() response.Header().Set("Content-Type", "text/plain") response.Write([]byte(fmt.Sprintf("Length: %d\n", len(keys)))) for _, v := range keys { response.Write([]byte(fmt.Sprintf("%#v\n", v))) if plan, ok := plr.plans.Get(v); ok { if b, err := json.MarshalIndent(plan, "", " "); err != nil { response.Write([]byte(err.Error())) } else { response.Write(b) } response.Write(([]byte)("\n\n")) } } } else if request.URL.Path == "/debug/schema" { response.Header().Set("Content-Type", "application/json; charset=utf-8") b, err := json.MarshalIndent(plr.schema, "", " ") if err != nil { response.Write([]byte(err.Error())) return } buf := bytes.NewBuffer(nil) json.HTMLEscape(buf, b) response.Write(buf.Bytes()) } else { response.WriteHeader(http.StatusNotFound) } }
func (ar *ActionRepository) ApplyTabletAction(actionName string, tabletAlias topo.TabletAlias, r *http.Request) *ActionResult { result := &ActionResult{Name: actionName, Parameters: tabletAlias.String()} action, ok := ar.tabletActions[actionName] if !ok { result.error("Unknown tablet action") return result } // check the role if action.role != "" { if err := acl.CheckAccessHTTP(r, action.role); err != nil { result.error("Access denied") return result } } // run the action wr := wrangler.New(logutil.NewConsoleLogger(), ar.ts, *actionTimeout, *lockTimeout) output, err := action.method(wr, tabletAlias, r) if err != nil { result.error(err.Error()) return result } result.Output = output return result }
func healthCheck(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.MONITORING); err != nil { acl.SendError(w, err) return } w.Header().Set("Content-Type", "text/plain") if err := IsHealthy(); err != nil { w.Write([]byte("not ok")) return } w.Write([]byte("ok")) }
func (ar ActionRepository) PopulateTabletActions(actions map[string]template.URL, tabletAlias string, r *http.Request) { for name, value := range ar.tabletActions { // check we are authorized for the role we need if value.role != "" { if err := acl.CheckAccessHTTP(r, value.role); err != nil { continue } } // and populate the entry values := url.Values{} values.Set("action", name) values.Set("alias", tabletAlias) actions[name] = template.URL("/tablet_actions?" + values.Encode()) } }
func (co *Consolidator) ServeHTTP(response http.ResponseWriter, request *http.Request) { if err := acl.CheckAccessHTTP(request, acl.DEBUGGING); err != nil { acl.SendError(response, err) return } items := co.consolidations.Items() response.Header().Set("Content-Type", "text/plain") if items == nil { response.Write([]byte("empty\n")) return } response.Write([]byte(fmt.Sprintf("Length: %d\n", len(items)))) for _, v := range items { response.Write([]byte(fmt.Sprintf("%v: %s\n", v.Value.(*ccount).Get(), v.Key))) } }
// txlogzHandler serves a human readable snapshot of the // current transaction log. func txlogzHandler(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return } ch := TxLogger.Subscribe("txlogz") defer TxLogger.Unsubscribe(ch) startHTMLTable(w) defer endHTMLTable(w) w.Write(txlogzHeader) tmr := time.NewTimer(10 * time.Second) defer tmr.Stop() for i := 0; i < 300; i++ { select { case out := <-ch: txc, ok := out.(*TxConnection) if !ok { err := fmt.Errorf("Unexpected value in %s: %#v (expecting value of type %T)", TxLogger.Name(), out, &TxConnection{}) io.WriteString(w, `<tr class="error">`) io.WriteString(w, err.Error()) io.WriteString(w, "</tr>") log.Error(err) continue } duration := txc.EndTime.Sub(txc.StartTime).Seconds() var level string if duration < 0.1 { level = "low" } else if duration < 1.0 { level = "medium" } else { level = "high" } tmplData := struct { *TxConnection Duration float64 ColorLevel string }{txc, duration, level} txlogzTmpl.Execute(w, tmplData) case <-tmr.C: return } } }
// queryzHandler displays the query stats. func queryzHandler(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return } startHTMLTable(w) defer endHTMLTable(w) w.Write(queryzHeader) si := SqlQueryRpcService.qe.schemaInfo keys := si.queries.Keys() sorter := queryzSorter{ rows: make([]*queryzRow, 0, len(keys)), less: func(row1, row2 *queryzRow) bool { return row1.timePQ() > row2.timePQ() }, } for _, v := range si.queries.Keys() { plan := si.getQuery(v) if plan == nil { continue } Value := &queryzRow{ Query: wrappable(v), Table: plan.TableName, Plan: plan.PlanId, Reason: plan.Reason, } Value.Count, Value.tm, Value.Rows, Value.Errors = plan.Stats() timepq := time.Duration(int64(Value.tm) / Value.Count) if timepq < 10*time.Millisecond { Value.Color = "low" } else if timepq < 100*time.Millisecond { Value.Color = "medium" } else { Value.Color = "high" } sorter.rows = append(sorter.rows, Value) } sort.Sort(&sorter) for _, Value := range sorter.rows { queryzTmpl.Execute(w, Value) } }
// querylogzHandler serves a human readable snapshot of the // current query log. func querylogzHandler(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return } ch := SqlQueryLogger.Subscribe("querylogz") defer SqlQueryLogger.Unsubscribe(ch) startHTMLTable(w) defer endHTMLTable(w) w.Write(querylogzHeader) tmr := time.NewTimer(10 * time.Second) defer tmr.Stop() for i := 0; i < 300; i++ { select { case out := <-ch: stats, ok := out.(*SQLQueryStats) if !ok { err := fmt.Errorf("Unexpected value in %s: %#v (expecting value of type %T)", TxLogger.Name(), out, &SQLQueryStats{}) io.WriteString(w, `<tr class="error">`) io.WriteString(w, err.Error()) io.WriteString(w, "</tr>") log.Error(err) continue } var level string if stats.TotalTime().Seconds() < 0.01 { level = "low" } else if stats.TotalTime().Seconds() < 0.1 { level = "medium" } else { level = "high" } tmplData := struct { *SQLQueryStats ColorLevel string }{stats, level} querylogzTmpl.Execute(w, tmplData) case <-tmr.C: return } } }
func streamqueryzTerminateHandler(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil { acl.SendError(w, err) return } if err := r.ParseForm(); err != nil { http.Error(w, fmt.Sprintf("cannot parse form: %s", err), http.StatusInternalServerError) return } connID := r.FormValue("connID") c, err := strconv.Atoi(connID) if err != nil { http.Error(w, "invalid connID", http.StatusInternalServerError) return } if err = SqlQueryRpcService.qe.streamQList.Terminate(int64(c)); err != nil { http.Error(w, fmt.Sprintf("error: %v", err), http.StatusInternalServerError) return } streamqueryzHandler(w, r) }
func statusHandler(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return } statusMu.Lock() defer statusMu.Unlock() data := struct { Sections []section BinaryName string Hostname string StartTime string }{ Sections: statusSections, BinaryName: binaryName, Hostname: hostname, StartTime: serverStart.Format(time.RFC1123), } if err := statusTmpl.ExecuteTemplate(w, "status", data); err != nil { log.Errorf("servenv: couldn't execute template: %v", err) } }
func (si *SchemaInfo) ServeHTTP(response http.ResponseWriter, request *http.Request) { if err := acl.CheckAccessHTTP(request, acl.DEBUGGING); err != nil { acl.SendError(response, err) return } if request.URL.Path == "/debug/query_plans" { keys := si.queries.Keys() response.Header().Set("Content-Type", "text/plain") response.Write([]byte(fmt.Sprintf("Length: %d\n", len(keys)))) for _, v := range keys { response.Write([]byte(fmt.Sprintf("%#v\n", v))) if plan := si.getQuery(v); plan != nil { if b, err := json.MarshalIndent(plan.ExecPlan, "", " "); err != nil { response.Write([]byte(err.Error())) } else { response.Write(b) } response.Write(([]byte)("\n\n")) } } } else if request.URL.Path == "/debug/query_stats" { keys := si.queries.Keys() response.Header().Set("Content-Type", "application/json; charset=utf-8") qstats := make([]perQueryStats, 0, len(keys)) for _, v := range keys { if plan := si.getQuery(v); plan != nil { var pqstats perQueryStats pqstats.Query = unicoded(v) pqstats.Table = plan.TableName pqstats.Plan = plan.PlanId pqstats.QueryCount, pqstats.Time, pqstats.RowCount, pqstats.ErrorCount = plan.Stats() qstats = append(qstats, pqstats) } } if b, err := json.MarshalIndent(qstats, "", " "); err != nil { response.Write([]byte(err.Error())) } else { response.Write(b) } } else if request.URL.Path == "/debug/table_stats" { response.Header().Set("Content-Type", "application/json; charset=utf-8") tstats := make(map[string]struct{ hits, absent, misses, invalidations int64 }) var temp, totals struct{ hits, absent, misses, invalidations int64 } func() { si.mu.Lock() defer si.mu.Unlock() for k, v := range si.tables { if v.CacheType != schema.CACHE_NONE { temp.hits, temp.absent, temp.misses, temp.invalidations = v.Stats() tstats[k] = temp totals.hits += temp.hits totals.absent += temp.absent totals.misses += temp.misses totals.invalidations += temp.invalidations } } }() response.Write([]byte("{\n")) for k, v := range tstats { fmt.Fprintf(response, "\"%s\": {\"Hits\": %v, \"Absent\": %v, \"Misses\": %v, \"Invalidations\": %v},\n", k, v.hits, v.absent, v.misses, v.invalidations) } fmt.Fprintf(response, "\"Totals\": {\"Hits\": %v, \"Absent\": %v, \"Misses\": %v, \"Invalidations\": %v}\n", totals.hits, totals.absent, totals.misses, totals.invalidations) response.Write([]byte("}\n")) } else if request.URL.Path == "/debug/schema" { response.Header().Set("Content-Type", "application/json; charset=utf-8") tables := si.GetSchema() b, err := json.MarshalIndent(tables, "", " ") if err != nil { response.Write([]byte(err.Error())) return } buf := bytes.NewBuffer(nil) json.HTMLEscape(buf, b) response.Write(buf.Bytes()) } else { response.WriteHeader(http.StatusNotFound) } }