mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-02-09 15:27:11 +00:00
lib/httpserver: log remote address in error message from httpserver.Errorf
This should improve detection of the root cause of errors. Thanks to Anant for the idea.
This commit is contained in:
parent
1c641037e8
commit
b35cb293f5
8 changed files with 52 additions and 46 deletions
|
@ -136,7 +136,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
prometheusWriteRequests.Inc()
|
prometheusWriteRequests.Inc()
|
||||||
if err := promremotewrite.InsertHandler(r); err != nil {
|
if err := promremotewrite.InsertHandler(r); err != nil {
|
||||||
prometheusWriteErrors.Inc()
|
prometheusWriteErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -145,7 +145,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
vmimportRequests.Inc()
|
vmimportRequests.Inc()
|
||||||
if err := vmimport.InsertHandler(r); err != nil {
|
if err := vmimport.InsertHandler(r); err != nil {
|
||||||
vmimportErrors.Inc()
|
vmimportErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -154,7 +154,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
csvimportRequests.Inc()
|
csvimportRequests.Inc()
|
||||||
if err := csvimport.InsertHandler(r); err != nil {
|
if err := csvimport.InsertHandler(r); err != nil {
|
||||||
csvimportErrors.Inc()
|
csvimportErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -163,7 +163,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
prometheusimportRequests.Inc()
|
prometheusimportRequests.Inc()
|
||||||
if err := prometheusimport.InsertHandler(r); err != nil {
|
if err := prometheusimport.InsertHandler(r); err != nil {
|
||||||
prometheusimportErrors.Inc()
|
prometheusimportErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -172,7 +172,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
influxWriteRequests.Inc()
|
influxWriteRequests.Inc()
|
||||||
if err := influx.InsertHandlerForHTTP(r); err != nil {
|
if err := influx.InsertHandlerForHTTP(r); err != nil {
|
||||||
influxWriteErrors.Inc()
|
influxWriteErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
|
|
@ -27,7 +27,6 @@ var pathList = [][]string{
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
|
func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
resph := responseHandler{w}
|
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/":
|
case "/":
|
||||||
for _, path := range pathList {
|
for _, path := range pathList {
|
||||||
|
@ -36,10 +35,22 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case "/api/v1/groups":
|
case "/api/v1/groups":
|
||||||
resph.handle(rh.listGroups())
|
data, err := rh.listGroups()
|
||||||
|
if err != nil {
|
||||||
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(data)
|
||||||
return true
|
return true
|
||||||
case "/api/v1/alerts":
|
case "/api/v1/alerts":
|
||||||
resph.handle(rh.listAlerts())
|
data, err := rh.listAlerts()
|
||||||
|
if err != nil {
|
||||||
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(data)
|
||||||
return true
|
return true
|
||||||
case "/-/reload":
|
case "/-/reload":
|
||||||
logger.Infof("api config reload was called, sending sighup")
|
logger.Infof("api config reload was called, sending sighup")
|
||||||
|
@ -47,12 +58,18 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
|
if !strings.HasSuffix(r.URL.Path, "/status") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
// /api/v1/<groupName>/<alertID>/status
|
// /api/v1/<groupName>/<alertID>/status
|
||||||
if strings.HasSuffix(r.URL.Path, "/status") {
|
data, err := rh.alert(r.URL.Path)
|
||||||
resph.handle(rh.alert(r.URL.Path))
|
if err != nil {
|
||||||
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(data)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,18 +168,6 @@ func (rh *requestHandler) alert(path string) ([]byte, error) {
|
||||||
return json.Marshal(resp)
|
return json.Marshal(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// responseHandler wrapper on http.ResponseWriter with sugar
|
|
||||||
type responseHandler struct{ http.ResponseWriter }
|
|
||||||
|
|
||||||
func (w responseHandler) handle(b []byte, err error) {
|
|
||||||
if err != nil {
|
|
||||||
httpserver.Errorf(w, "%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func uint64FromPath(path string) (uint64, error) {
|
func uint64FromPath(path string) (uint64, error) {
|
||||||
s := strings.TrimRight(path, "/")
|
s := strings.TrimRight(path, "/")
|
||||||
return strconv.ParseUint(s, 10, 0)
|
return strconv.ParseUint(s, 10, 0)
|
||||||
|
|
|
@ -49,20 +49,20 @@ func main() {
|
||||||
func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
username, password, ok := r.BasicAuth()
|
username, password, ok := r.BasicAuth()
|
||||||
if !ok {
|
if !ok {
|
||||||
httpserver.Errorf(w, "Missing `Authorization: Basic *` header")
|
httpserver.Errorf(w, r, "missing `Authorization: Basic *` header")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
ac := authConfig.Load().(map[string]*UserInfo)
|
ac := authConfig.Load().(map[string]*UserInfo)
|
||||||
info := ac[username]
|
info := ac[username]
|
||||||
if info == nil || info.Password != password {
|
if info == nil || info.Password != password {
|
||||||
httpserver.Errorf(w, "Cannot find the provided username %q or password in config", username)
|
httpserver.Errorf(w, r, "cannot find the provided username %q or password in config", username)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
info.requests.Inc()
|
info.requests.Inc()
|
||||||
|
|
||||||
targetURL := createTargetURL(info.URLPrefix, r.URL)
|
targetURL := createTargetURL(info.URLPrefix, r.URL)
|
||||||
if _, err := url.Parse(targetURL); err != nil {
|
if _, err := url.Parse(targetURL); err != nil {
|
||||||
httpserver.Errorf(w, "Invalid targetURL=%q: %s", targetURL, err)
|
httpserver.Errorf(w, r, "invalid targetURL=%q: %s", targetURL, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
r.Header.Set("vm-target-url", targetURL)
|
r.Header.Set("vm-target-url", targetURL)
|
||||||
|
|
|
@ -92,7 +92,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
prometheusWriteRequests.Inc()
|
prometheusWriteRequests.Inc()
|
||||||
if err := promremotewrite.InsertHandler(r); err != nil {
|
if err := promremotewrite.InsertHandler(r); err != nil {
|
||||||
prometheusWriteErrors.Inc()
|
prometheusWriteErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -101,7 +101,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
vmimportRequests.Inc()
|
vmimportRequests.Inc()
|
||||||
if err := vmimport.InsertHandler(r); err != nil {
|
if err := vmimport.InsertHandler(r); err != nil {
|
||||||
vmimportErrors.Inc()
|
vmimportErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -110,7 +110,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
csvimportRequests.Inc()
|
csvimportRequests.Inc()
|
||||||
if err := csvimport.InsertHandler(r); err != nil {
|
if err := csvimport.InsertHandler(r); err != nil {
|
||||||
csvimportErrors.Inc()
|
csvimportErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -119,7 +119,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
prometheusimportRequests.Inc()
|
prometheusimportRequests.Inc()
|
||||||
if err := prometheusimport.InsertHandler(r); err != nil {
|
if err := prometheusimport.InsertHandler(r); err != nil {
|
||||||
prometheusimportErrors.Inc()
|
prometheusimportErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
@ -128,7 +128,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
influxWriteRequests.Inc()
|
influxWriteRequests.Inc()
|
||||||
if err := influx.InsertHandlerForHTTP(r); err != nil {
|
if err := influx.InsertHandlerForHTTP(r); err != nil {
|
||||||
influxWriteErrors.Inc()
|
influxWriteErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
|
|
@ -90,7 +90,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
*maxConcurrentRequests, *maxQueueDuration),
|
*maxConcurrentRequests, *maxQueueDuration),
|
||||||
StatusCode: http.StatusServiceUnavailable,
|
StatusCode: http.StatusServiceUnavailable,
|
||||||
}
|
}
|
||||||
httpserver.Errorf(w, "%s", err)
|
httpserver.Errorf(w, r, "%s", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
exportRequests.Inc()
|
exportRequests.Inc()
|
||||||
if err := prometheus.ExportHandler(startTime, w, r); err != nil {
|
if err := prometheus.ExportHandler(startTime, w, r); err != nil {
|
||||||
exportErrors.Inc()
|
exportErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -199,7 +199,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
federateRequests.Inc()
|
federateRequests.Inc()
|
||||||
if err := prometheus.FederateHandler(startTime, w, r); err != nil {
|
if err := prometheus.FederateHandler(startTime, w, r); err != nil {
|
||||||
federateErrors.Inc()
|
federateErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -225,12 +225,12 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
deleteRequests.Inc()
|
deleteRequests.Inc()
|
||||||
authKey := r.FormValue("authKey")
|
authKey := r.FormValue("authKey")
|
||||||
if authKey != *deleteAuthKey {
|
if authKey != *deleteAuthKey {
|
||||||
httpserver.Errorf(w, "invalid authKey %q. It must match the value from -deleteAuthKey command line flag", authKey)
|
httpserver.Errorf(w, r, "invalid authKey %q. It must match the value from -deleteAuthKey command line flag", authKey)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if err := prometheus.DeleteHandler(startTime, r); err != nil {
|
if err := prometheus.DeleteHandler(startTime, r); err != nil {
|
||||||
deleteErrors.Inc()
|
deleteErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", r.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
|
|
@ -181,7 +181,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||||
}
|
}
|
||||||
authKey := r.FormValue("authKey")
|
authKey := r.FormValue("authKey")
|
||||||
if authKey != *snapshotAuthKey {
|
if authKey != *snapshotAuthKey {
|
||||||
httpserver.Errorf(w, "invalid authKey %q. It must match the value from -snapshotAuthKey command line flag", authKey)
|
httpserver.Errorf(w, r, "invalid authKey %q. It must match the value from -snapshotAuthKey command line flag", authKey)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
path = path[len("/snapshot"):]
|
path = path[len("/snapshot"):]
|
||||||
|
|
|
@ -172,7 +172,7 @@ func handlerWrapper(s *server, w http.ResponseWriter, r *http.Request, rh Reques
|
||||||
requestsTotal.Inc()
|
requestsTotal.Inc()
|
||||||
path, err := getCanonicalPath(r.URL.Path)
|
path, err := getCanonicalPath(r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Errorf(w, "cannot get canonical path: %s", err)
|
Errorf(w, r, "cannot get canonical path: %s", err)
|
||||||
unsupportedRequestErrors.Inc()
|
unsupportedRequestErrors.Inc()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,7 @@ func handlerWrapper(s *server, w http.ResponseWriter, r *http.Request, rh Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Errorf(w, "unsupported path requested: %q", r.URL.Path)
|
Errorf(w, r, "unsupported path requested: %q", r.URL.Path)
|
||||||
unsupportedRequestErrors.Inc()
|
unsupportedRequestErrors.Inc()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -482,8 +482,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errorf writes formatted error message to w and to logger.
|
// Errorf writes formatted error message to w and to logger.
|
||||||
func Errorf(w http.ResponseWriter, format string, args ...interface{}) {
|
func Errorf(w http.ResponseWriter, r *http.Request, format string, args ...interface{}) {
|
||||||
errStr := fmt.Sprintf(format, args...)
|
errStr := fmt.Sprintf(format, args...)
|
||||||
|
errStr = fmt.Sprintf("remoteAddr: %s; %s", r.RemoteAddr, errStr)
|
||||||
logger.WarnfSkipframes(1, "%s", errStr)
|
logger.WarnfSkipframes(1, "%s", errStr)
|
||||||
|
|
||||||
// Extract statusCode from args
|
// Extract statusCode from args
|
||||||
|
|
|
@ -28,7 +28,7 @@ type Server struct {
|
||||||
// MustStart starts HTTP OpenTSDB server on the given addr.
|
// MustStart starts HTTP OpenTSDB server on the given addr.
|
||||||
//
|
//
|
||||||
// MustStop must be called on the returned server when it is no longer needed.
|
// MustStop must be called on the returned server when it is no longer needed.
|
||||||
func MustStart(addr string, insertHandler func(req *http.Request) error) *Server {
|
func MustStart(addr string, insertHandler func(r *http.Request) error) *Server {
|
||||||
logger.Infof("starting HTTP OpenTSDB server at %q", addr)
|
logger.Infof("starting HTTP OpenTSDB server at %q", addr)
|
||||||
lnTCP, err := netutil.NewTCPListener("opentsdbhttp", addr)
|
lnTCP, err := netutil.NewTCPListener("opentsdbhttp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -40,7 +40,7 @@ func MustStart(addr string, insertHandler func(req *http.Request) error) *Server
|
||||||
// MustServe serves OpenTSDB HTTP put requests from ln.
|
// MustServe serves OpenTSDB HTTP put requests from ln.
|
||||||
//
|
//
|
||||||
// MustStop must be called on the returned server when it is no longer needed.
|
// MustStop must be called on the returned server when it is no longer needed.
|
||||||
func MustServe(ln net.Listener, insertHandler func(req *http.Request) error) *Server {
|
func MustServe(ln net.Listener, insertHandler func(r *http.Request) error) *Server {
|
||||||
h := newRequestHandler(insertHandler)
|
h := newRequestHandler(insertHandler)
|
||||||
hs := &http.Server{
|
hs := &http.Server{
|
||||||
Handler: h,
|
Handler: h,
|
||||||
|
@ -84,12 +84,12 @@ func (s *Server) MustStop() {
|
||||||
logger.Infof("OpenTSDB HTTP server at %q has been stopped", s.ln.Addr())
|
logger.Infof("OpenTSDB HTTP server at %q has been stopped", s.ln.Addr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRequestHandler(insertHandler func(req *http.Request) error) http.Handler {
|
func newRequestHandler(insertHandler func(r *http.Request) error) http.Handler {
|
||||||
rh := func(w http.ResponseWriter, req *http.Request) {
|
rh := func(w http.ResponseWriter, r *http.Request) {
|
||||||
writeRequests.Inc()
|
writeRequests.Inc()
|
||||||
if err := insertHandler(req); err != nil {
|
if err := insertHandler(r); err != nil {
|
||||||
writeErrors.Inc()
|
writeErrors.Inc()
|
||||||
httpserver.Errorf(w, "error in %q: %s", req.URL.Path, err)
|
httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
|
Loading…
Reference in a new issue