func buildsShowHandler(c web.C, w http.ResponseWriter, r *http.Request) { if db == nil { fmt.Fprintf(w, "database logging not enabled") return } id := fmt.Sprintf("%s/%s", c.URLParams["name"], c.URLParams["repo_tag"]) var build Build if err := build.Get(id); err != nil { w.Header().Set("Content-Type", "text/plain") switch err { case sql.ErrNoRows: log.Printf("[%s] build with id='%s' doesn't exist", middleware.GetReqID(c), id, err) http.Error(w, fmt.Sprintf("404 build %s not found", id), 404) default: log.Printf("[%s] error fetching build with id='%s': %v", middleware.GetReqID(c), id, err) http.Error(w, err.Error(), 500) } return } else { w.Header().Set("Content-Type", "text/html") fmt.Fprintf(w, "<p>← %s</p><h3>%s</h3><p>revision: %s<br>created: %s<br>completed: %s<br>success: %v %s<br>output:</p><pre>%s</pre>", linkTo("/", "all builds"), build.Id, githubRevisionLink(&build), build.CreatedAt, build.CompletedAt, build.Success, builderImgForBuild(&build), build.Output) } }
// Middleware that recovers from panics, sends email if a notification email // has been provided, and log issues. func recoverHandler(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { reqID := middleware.GetReqID(*c) defer func() { if err := recover(); err != nil { buf := make([]byte, 1<<16) size := runtime.Stack(buf, false) stackTrace := string(buf[0:size]) message := fmt.Sprintf("Panic detected on request %s:\n%+v\nIP: %v, URL: %s\nStack trace:\n%s\n", reqID, err, r.RemoteAddr, r.URL.Path, stackTrace) dvid.Criticalf("%s\n", message) if err := SendNotification(message, nil); err != nil { dvid.Criticalf("Couldn't send email notifcation: %v\n", err) } http.Error(w, http.StatusText(500), 500) } }() h.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
func (rec recoverer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { reqID := gmiddleware.GetReqID(*rec.c) defer func() { if r := recover(); r != nil { var err error switch x := r.(type) { case error: err = x default: err = fmt.Errorf("%v", x) } rec.l.WithFields(logrus.Fields{ "req_id": reqID, "method": req.Method, "uri": req.RequestURI, "remote": req.RemoteAddr, "err": err.Error(), "stack": stack.Callers(0), }).Warn("service.err") http.Error(resp, http.StatusText(500), 500) } }() rec.h.ServeHTTP(resp, req) }
func recoverer(c *web.C, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { id := middleware.GetReqID(*c) // Raven recoverer defer func() { var packet *raven.Packet switch rval := recover().(type) { case nil: return case error: packet = raven.NewPacket(rval.Error(), raven.NewHttp(r), raven.NewException(rval, raven.NewStacktrace(2, 3, nil))) default: str := fmt.Sprintf("%+v", rval) packet = raven.NewPacket(str, raven.NewHttp(r), raven.NewException(errors.New(str), raven.NewStacktrace(2, 3, nil))) } debug.PrintStack() http.Error(w, http.StatusText(500), 500) env.Raven.Capture(packet, map[string]string{ "request_id": id, }) }() h.ServeHTTP(w, r) }) }
func (ac *ActiveContext) InfoLog(msg string) { rID := middleware.GetReqID(ac.Context) ac.Logger.InfoWithFields(msg, map[string]interface{}{ "req_id": rID, "uri": ac.Request.RequestURI, }) }
// Logger returns a Goji web middleware that logs web transactions in the format // I want. func Logger(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { startTime := time.Now() fields := log.Fields{ "requestId": middleware.GetReqID(*c), "client": r.RemoteAddr, "url": r.URL.String(), "method": r.Method, "protocol": r.Proto, "referer": r.Referer(), "start": startTime, } log.WithFields(fields).Debug("Request started.") lw := mutil.WrapWriter(w) h.ServeHTTP(lw, r) endTime := time.Now() duration := endTime.Sub(startTime) fields["duration"] = duration.Nanoseconds() status := lw.Status() fields["status"] = status switch { case status < 300: // 100- and 200-series statuses log.WithFields(fields).Info("OK") case status < 400: // 300-series redirection log.WithFields(fields).Info("Redirected") case status < 500: // 400-series client error log.WithFields(fields).Warn("Client error") default: // 500-series server erorr log.WithFields(fields).Error("Server error!") } } return http.HandlerFunc(fn) }
func (glogr glogrus) ServeHTTP(resp http.ResponseWriter, req *http.Request) { start := time.Now() reqID := middleware.GetReqID(*glogr.c) glogr.l.WithFields(logrus.Fields{ "req_id": reqID, "uri": req.RequestURI, "method": req.Method, "remote": req.RemoteAddr, }).Info("New request incoming") lresp := wrapWriter(resp) glogr.h.ServeHTTP(lresp, req) lresp.maybeWriteHeader() latency := float64(time.Since(start)) / float64(time.Millisecond) glogr.l.WithFields(logrus.Fields{ "req_id": reqID, "status": lresp.status(), "method": req.Method, "uri": req.RequestURI, "remote": req.RemoteAddr, "latency": fmt.Sprintf("%6.4f ms", latency), "app": glogr.name, }).Info("Finished serving the request") }
func (ac *ActiveContext) ParamsLog(params interface{}) { rid := middleware.GetReqID(ac.Context) uri := ac.Request.RequestURI ac.Logger.ParamsWithFields(params, map[string]interface{}{ "datetime": time.Now().Format("2006-01-02 15:04:05"), "req_id": rid, "uri": uri, }) }
//Route is used because our handlers returns *app.Err func (b *BaseHandler) Route(h AppH) func(web.C, http.ResponseWriter, *http.Request) { fn := func(c web.C, w http.ResponseWriter, r *http.Request) { err := h(c, w, r) if err != nil { reqID := gmiddleware.GetReqID(c) b.Logr.WithFields(logrus.Fields{ "req_id": reqID, "err": err.Error(), }).Error("response.err") http.Error(w, http.StatusText(err.HTTPStatus), err.HTTPStatus) } } return fn }
func buildsIndexHandler(c web.C, w http.ResponseWriter, r *http.Request) { if db == nil { fmt.Fprintf(w, "database logging not enabled") return } builds := []Build{} err := db.Select(&builds, "SELECT * FROM builds ORDER BY created_at DESC") if err != nil { log.Printf("[%s] error listing builds: %v", middleware.GetReqID(c), err) http.Error(w, err.Error(), 500) return } w.Header().Set("Content-Type", "text/html") fmt.Fprintf(w, "all builds: <br>") for _, build := range builds { fmt.Fprintf(w, "%s <a href='/%s'>%s</a> created at %s <br>", builderImgForBuild(&build), build.Id, build.Id, build.CreatedAt) } }
// RequestIDHeader adds a Request-Id in response header. func RequestIDHeader(c *web.C, h http.Handler) http.Handler { fn := func(resp http.ResponseWriter, req *http.Request) { var requestID string given := req.Header.Get("X-Request-Id") if given != "" { requestID = given } given = req.Header.Get("Request-Id") if given != "" { requestID = given } if requestID == "" && c.Env["requestID"] != "" { requestID = gmiddleware.GetReqID(*c) } resp.Header().Set("Request-Id", requestID) h.ServeHTTP(resp, req) } return http.HandlerFunc(fn) }
func (ac *ActiveContext) ErrorLog(e error) { rID := middleware.GetReqID(ac.Context) if ac.Env == EnvDevelopment { stack := make([]byte, 4096) read := runtime.Stack(stack, false) ac.Logger.ErrorWithFields(e, map[string]interface{}{ "datetime": time.Now().Format("2006-01-02 15:04:05"), "req_id": rID, "uri": ac.Request.RequestURI, "stacktrace": string(stack[:read]), }) } else { ac.Logger.ErrorWithFields(e, map[string]interface{}{ "datetime": time.Now().Format("2006-01-02 15:04:05"), "req_id": rID, "uri": ac.Request.RequestURI, }) } }
// LoggerMiddleware is the middleware that logs http requests and resposnes // to the logging subsytem of horizon. func LoggerMiddleware(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { ctx := gctx.FromC(*c) mw := mutil.WrapWriter(w) logger := log.WithField("req", middleware.GetReqID(*c)) ctx = log.Set(ctx, logger) gctx.Set(c, ctx) logStartOfRequest(ctx, r) then := time.Now() h.ServeHTTP(mw, r) duration := time.Now().Sub(then) logEndOfRequest(ctx, duration, mw) } return http.HandlerFunc(fn) }
// ContextFromC returns a new context bound with the value of the request id in // the provide goji context func ContextFromC(ctx context.Context, c *web.C) context.Context { reqid := middleware.GetReqID(*c) return Context(ctx, reqid) }
func logForReq(c web.C, message string) { log.Printf("[%s] %s", middleware.GetReqID(c), message) }
// instanceSelector retrieves the data instance given its complete string name and // forwards the request to that instance's HTTP handler. func instanceSelector(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { if httpUnavailable(w) { return } var err error dataname := dvid.InstanceName(c.URLParams["dataname"]) uuid, ok := c.Env["uuid"].(dvid.UUID) if !ok { msg := fmt.Sprintf("Bad format for UUID %q\n", c.Env["uuid"]) BadRequest(w, r, msg) return } data, err := datastore.GetDataByUUIDName(uuid, dataname) if err != nil { BadRequest(w, r, err) return } v, err := datastore.VersionFromUUID(uuid) if err != nil { BadRequest(w, r, err) return } if data.Versioned() { // Make sure we aren't trying mutable methods on committed nodes. locked, err := datastore.LockedUUID(uuid) if err != nil { BadRequest(w, r, err) return } if locked && data.IsMutationRequest(r.Method, c.URLParams["keyword"]) { BadRequest(w, r, "Cannot do %s on endpoint %q of locked node %s", r.Method, c.URLParams["keyword"], uuid) return } } else { // Map everything to root version. v, err = datastore.GetRepoRootVersion(v) if err != nil { BadRequest(w, r, err) return } } ctx := datastore.NewVersionedCtx(data, v) // Also set the web request information in case logging needs it downstream. ctx.SetRequestID(middleware.GetReqID(*c)) // Handle DVID-wide query string commands like non-interactive call designations queryStrings := r.URL.Query() // All HTTP requests are interactive so let server tally request. interactive := queryStrings.Get("interactive") if interactive == "" || (interactive != "false" && interactive != "0") { GotInteractiveRequest() } // TODO: setup routing for data instances as well. if config != nil && config.AllowTiming() { w.Header().Set("Timing-Allow-Origin", "*") } data.ServeHTTP(uuid, ctx, w, r) } return http.HandlerFunc(fn) }