diff --git a/commands/commands.go b/commands/commands.go index b0b6b26d..41b4d3c0 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -141,6 +141,9 @@ func logPanic(loggedError error, recursive bool) string { if wErr, ok := loggedError.(ErrorWithStack); ok { fmt.Fprintln(fmtWriter, wErr.InnerError()) + for key, value := range wErr.Context() { + fmt.Fprintf(fmtWriter, "%s=%s\n", key, value) + } fmtWriter.Write(wErr.Stack()) } else { fmtWriter.Write(gitmedia.Stack()) @@ -155,6 +158,7 @@ func logPanic(loggedError error, recursive bool) string { } type ErrorWithStack interface { + Context() map[string]string InnerError() string Stack() []byte } diff --git a/gitmedia/errors.go b/gitmedia/errors.go index df4f1489..d64d7f8e 100644 --- a/gitmedia/errors.go +++ b/gitmedia/errors.go @@ -9,6 +9,7 @@ type WrappedError struct { Err error Message string stack []byte + context map[string]string } func Error(err error) *WrappedError { @@ -33,6 +34,27 @@ func Errorf(err error, format string, args ...interface{}) *WrappedError { return e } +func (e *WrappedError) Set(key, value string) { + if e.context == nil { + e.context = make(map[string]string) + } + e.context[key] = value +} + +func (e *WrappedError) Get(key string) string { + if e.context == nil { + return "" + } + return e.context[key] +} + +func (e *WrappedError) Del(key string) { + if e.context == nil { + return + } + delete(e.context, key) +} + func (e *WrappedError) Error() string { return e.Message } @@ -49,6 +71,13 @@ func (e *WrappedError) Stack() []byte { return e.stack } +func (e *WrappedError) Context() map[string]string { + if e.context == nil { + e.context = make(map[string]string) + } + return e.context +} + func Stack() []byte { stackBuf := make([]byte, 1024*1024) written := runtime.Stack(stackBuf, false) diff --git a/gitmediaclient/client.go b/gitmediaclient/client.go index 757cdb89..d1042d03 100644 --- a/gitmediaclient/client.go +++ b/gitmediaclient/client.go @@ -98,10 +98,10 @@ func Get(filename string) (io.ReadCloser, int64, *gitmedia.WrappedError) { } req.Header.Set("Accept", gitMediaType) - res, err := doRequest(req, creds) + res, wErr := doRequest(req, creds) if err != nil { - return nil, 0, gitmedia.Error(err) + return nil, 0, wErr } contentType := res.Header.Get("Content-Type") @@ -146,7 +146,7 @@ func validateMediaHeader(contentType string, reader io.Reader) (bool, error) { return true, nil } -func doRequest(req *http.Request, creds Creds) (*http.Response, error) { +func doRequest(req *http.Request, creds Creds) (*http.Response, *gitmedia.WrappedError) { res, err := http.DefaultClient.Do(req) if err == nil { @@ -159,16 +159,21 @@ func doRequest(req *http.Request, creds Creds) (*http.Response, error) { apierr := &Error{} dec := json.NewDecoder(res.Body) if err := dec.Decode(apierr); err != nil { - return res, err + return res, gitmedia.Errorf(err, "Error decoding JSON from response") } - return res, apierr + return res, gitmedia.Errorf(apierr, "Invalid response: %d", res.StatusCode) } execCreds(creds, "approve") } - return res, err + wErr := gitmedia.Errorf(err, "Error sending HTTP request to %s", req.URL.String()) + wErr.Set("URL", req.URL.String()) + for key, _ := range req.Header { + wErr.Set(key, req.Header.Get(key)) + } + return res, wErr } func clientRequest(method, oid string) (*http.Request, Creds, error) {