// Data returns a JSON response with the provided data and HTTP status // code. func Data(ctx context.Context, w http.ResponseWriter, status int, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(data); isBrokenPipe(err) { reqlog.Print(ctx, "unable to respond to client. event=respond_broken_pipe") metrics.Increment("respond_broken_pipe") } else if err != nil { panic(err) } }
// WrapPanicC wraps a goji.Handler to catch panics, log relevant // information and return an InternalFailure to the user. func WrapPanicC(h goji.Handler) goji.Handler { return goji.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { defer func() { err := recover() if err == nil { return } metrics.Increment("http.panics") id := fmt.Sprintf("%016x", rand.Int63()) var lines []string first := "event=panic" pc, file, line, ok := runtime.Caller(3) if ok { f := runtime.FuncForPC(pc) first = fmt.Sprintf("%s:%d %s() %s", file, line, f.Name(), first) } lines = append(lines, first) if wrapped, ok := err.(*errors.Err); ok { for _, line := range wrapped.StackTrace() { lines = append(lines, line) } } if len(lines) > 1 { logMutex.Lock() defer logMutex.Unlock() } for _, line := range lines { reqlog.Printf(ctx, "(panic=%s) %s", id, line) } Error(ctx, w, http.StatusInternalServerError, usererrors.InternalFailure{id}) }() h.ServeHTTPC(ctx, w, r) }) }
// WrapPanicC wraps a goji.Handler to catch panics, log relevant // information and return an InternalFailure to the user. func WrapPanicC(h goji.Handler) goji.Handler { return goji.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { defer func() { recovered := recover() if recovered == nil { return } err, ok := recovered.(error) if !ok { err = fmt.Errorf("%s", err) } metrics.Increment("http.panics") logError(ctx, err, "panic") UserError(ctx, w, http.StatusInternalServerError, usererrors.InternalFailure{}) }() h.ServeHTTPC(ctx, w, r) }) }