func Details(err error) string {
	if err == nil {
		return "[]"
	}
	var s []byte
	s = append(s, '[')
	for {
		s = append(s, '{')
		if err, ok := err.(Locationer); ok {
			loc := err.Location()
			if loc.IsSet() {
				s = append(s, loc.String()...)
				s = append(s, ": "...)
			}
		}
		if cerr, ok := err.(Wrapper); ok {
			s = append(s, cerr.Message()...)
			err = cerr.Underlying()
		} else {
			s = append(s, err.Error()...)
			err = nil
		}
		if debug {
			if err, ok := err.(Causer); ok {
				if cause := err.Cause(); cause != nil {
					s = append(s, fmt.Sprintf("=%T", cause)...)
					s = append(s, Details(cause)...)
				}
			}
		}
		s = append(s, '}')
		if err == nil {
			break
		}
		s = append(s, ' ')
	}
	s = append(s, ']')
	return string(s)
}
Details returns information about the stack of
underlying errors wrapped by err, in the format:

[{filename:99: error one} {otherfile:55: cause of error one}]

The details are found by type-asserting the error to
the Locationer, Causer and Wrapper interfaces.
Details of the underlying stack are found by
recursively calling Underlying when the
underlying error implements Wrapper.
package errgo
import (
	"bytes"
	"fmt"
	"log"
	"runtime"
)
const debug = false
type Location struct {
	File string
	Line int
}
func (loc Location) String() string {
	return fmt.Sprintf("%s:%d", loc.File, loc.Line)
}
func (loc Location) IsSet() bool {
	return loc.File != ""
}
type Err struct {
	Message_ string
	Cause_ error
	Underlying_ error
	Location_ Location
}
func (e *Err) Location() Location {
	return e.Location_
}
func (e *Err) Underlying() error {
	return e.Underlying_
}
func (e *Err) Cause() error {
	return e.Cause_
}
func (e *Err) Message() string {
	return e.Message_
}
func (e *Err) Error() string {
	switch {
	case e.Message_ == "" && e.Underlying_ == nil:
		return "<no error>"
	case e.Message_ == "":
		return e.Underlying_.Error()
	case e.Underlying_ == nil:
		return e.Message_
	}
	return fmt.Sprintf("%s: %v", e.Message_, e.Underlying_)
}
func (e *Err) GoString() string {
	return Details(e)
}
type Causer interface {
	Cause() error
}
type Wrapper interface {
	Message() string
	Underlying() error
}
type Locationer interface {
	Location() Location
}