func Pf(w io.Writer, r *http.Request, f string, vs ...interface{}) { for idx, v := range vs { switch v := v.(type) { case []byte: if len(v) > 1024*5 { appdx := append([]byte(" ...omitted... "), v[len(v)-100:]...) vs[idx] = append(v[:1024*5], appdx...) } case string: if len(v) > 1024*5 { appdx := " ...omitted... " + v[len(v)-100:] vs[idx] = v[:1024*5] + appdx } } } // Prepare the string var s string if len(vs) > 0 { s = fmt.Sprintf(f, vs...) } else { s = f } if s == "" { return } // Write it to http response or bytes.Buffer // unless prefixed with 'lo ' - log only. // Thread-safety could be introduced by syncing/locking w. if w != nil && !strings.HasPrefix(s, "lo ") { w.Write([]byte(s)) w.Write([]byte{'\n'}) } // Write to log/gae-log // Adding src code info line, file := runtimepb.LineFileXUp(1) // if strings.HasSuffix(file, "log.go") if strings.HasSuffix(file, runtimepb.ThisFile()) { // change line, file = runtimepb.LineFileXUp(2) } if len(s) < 60 { s = stringspb.ToLen(s, 60) } s = fmt.Sprintf("%v - %v:%v", s, file, line) // Log it c, _ := util_appengine.SafelyExtractGaeCtxError(r) if c == nil { lnp.Printf(s) } else { aelog.Infof(c, s) } }
/* A generic error function Utility functions pass errors up to the caller Higher level "request functions" handle errors directly often we want to abort further request processing and issue an message into the http response AND into the logs Sometimes we only want to write the error into the logs and continue operation => continueExecution true In addition to the generic error messages we may add specific error explanations or values via parameter vs - for display and logging We also show the source file+location. A "global panic catcher" in util_err.Adapter() ...defer(){} cooperates - suppressing the stacktrace and healing the panic */ func E(w http.ResponseWriter, r *http.Request, bool_or_err interface{}, continueExecution bool, vs ...interface{}) { var err error switch bool_or_err.(type) { default: type_unknown := fmt.Sprintf("%T", bool_or_err) err = errors.New("only bool or error - instead: -" + type_unknown + "-") panic(err) case nil: return case bool: if bool_or_err.(bool) { return } err = errors.New("Not OK (type conv?)") case error: err = bool_or_err.(error) } if err != nil { line, file := runtimepb.LineFileXUp(1) // we cannot determine, whether html is already sent // we cannot determine, whether we are in plaintext or html context // thus we need the <br> s := fmt.Sprintf("ERR: %v <br>\n\t /%s:%d \n", err, file, line) if len(vs) > 0 { s = s + "\t" + fmt.Sprint(vs...) + "\n" } if continueExecution { c, _ := util_appengine.SafelyExtractGaeCtxError(r) if c == nil { log.Printf(s) } else { aelog.Infof(c, s) } } else { c, _ := util_appengine.SafelyExtractGaeCtxError(r) if c == nil { log.Printf(s) } else { aelog.Errorf(c, s) } w.Header().Set("Content-Type", "text/plain") http.Error(w, s, http.StatusInternalServerError) panic("abort_handler_processing") } } }