github.com/anishathalye/periscope@v0.3.5/internal/herror/herror.go (about)

     1  package herror
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"runtime"
     7  	"strings"
     8  )
     9  
    10  const maxStackDepth = 50
    11  
    12  type Interface interface {
    13  	error
    14  	Herror(debug bool) string
    15  }
    16  
    17  type base struct {
    18  	stackTrace string
    19  }
    20  
    21  func newBase() base {
    22  	stackBuf := make([]uintptr, maxStackDepth)
    23  	length := runtime.Callers(3, stackBuf[:])
    24  	stack := stackBuf[:length]
    25  	frames := runtime.CallersFrames(stack)
    26  	buf := new(bytes.Buffer)
    27  	for {
    28  		frame, more := frames.Next()
    29  		fn := frame.Function
    30  		if fn == "" {
    31  			fn = "???"
    32  		}
    33  		fmt.Fprintf(buf, "%s\n\t%s:%d\n", fn, frame.File, frame.Line)
    34  		if !more {
    35  			break
    36  		}
    37  	}
    38  	return base{buf.String()}
    39  }
    40  
    41  type silent struct {
    42  	base
    43  }
    44  
    45  func (s *silent) Error() string {
    46  	return ""
    47  }
    48  
    49  func (s *silent) Herror(debug bool) string {
    50  	if !debug {
    51  		return ""
    52  	}
    53  	return fmt.Sprintf("<silent error>\n--------\n%s--------\n", s.stackTrace)
    54  }
    55  
    56  func Silent() Interface {
    57  	return &silent{base: newBase()}
    58  }
    59  
    60  func IsSilent(e Interface) bool {
    61  	_, ok := e.(*silent)
    62  	return ok
    63  }
    64  
    65  type user struct {
    66  	base
    67  	err     error
    68  	message string
    69  }
    70  
    71  func (u *user) Error() string {
    72  	if u.err != nil {
    73  		return fmt.Sprintf("%s (%s)", u.message, u.err.Error())
    74  	}
    75  	return u.message
    76  }
    77  
    78  func (u *user) Herror(debug bool) string {
    79  	buf := new(bytes.Buffer)
    80  	fmt.Fprint(buf, u.message)
    81  	if u.err != nil {
    82  		fmt.Fprintf(buf, " (%s)", u.err.Error())
    83  	}
    84  	fmt.Fprintf(buf, "\n")
    85  	if debug {
    86  		fmt.Fprintf(buf, "--------\n%s--------\n", u.stackTrace)
    87  	}
    88  	return buf.String()
    89  }
    90  
    91  func User(err error, message string) Interface {
    92  	return &user{base: newBase(), err: err, message: strings.TrimSpace(message)}
    93  }
    94  
    95  func UserF(err error, message string, a ...interface{}) Interface {
    96  	return User(err, fmt.Sprintf(message, a...))
    97  }
    98  
    99  type unlikely struct {
   100  	base
   101  	err   error
   102  	short string
   103  	long  string
   104  }
   105  
   106  func (u *unlikely) Error() string {
   107  	if u.err != nil {
   108  		return fmt.Sprintf("%s (%s)", u.short, u.err.Error())
   109  	}
   110  	return u.short
   111  }
   112  
   113  func (u *unlikely) Herror(debug bool) string {
   114  	buf := new(bytes.Buffer)
   115  	fmt.Fprint(buf, u.short)
   116  	if u.err != nil {
   117  		fmt.Fprintf(buf, " (%s)", u.err.Error())
   118  	}
   119  	fmt.Fprint(buf, "\n")
   120  	if len(u.long) > 0 {
   121  		fmt.Fprintf(buf, "\n%s\n", u.long)
   122  	}
   123  	if debug {
   124  		fmt.Fprintf(buf, "--------\n%s--------\n", u.stackTrace)
   125  	}
   126  	return buf.String()
   127  }
   128  
   129  func Unlikely(err error, short string, long string) Interface {
   130  	return &unlikely{base: newBase(), short: strings.TrimSpace(short), err: err, long: strings.TrimSpace(long)}
   131  }
   132  
   133  type internal struct {
   134  	base
   135  	err     error
   136  	message string
   137  }
   138  
   139  func (i *internal) Error() string {
   140  	if i.message != "" {
   141  		return fmt.Sprintf("%s (%s)", i.message, i.err.Error())
   142  	}
   143  	return i.err.Error()
   144  }
   145  
   146  func (i *internal) Herror(debug bool) string {
   147  	buf := new(bytes.Buffer)
   148  	fmt.Fprint(buf, "internal error: ")
   149  	if i.message != "" {
   150  		fmt.Fprintf(buf, "%s (%s)\n", i.message, i.err.Error())
   151  	} else {
   152  		fmt.Fprintf(buf, "%s\n", i.err.Error())
   153  	}
   154  	if !debug {
   155  		fmt.Fprintf(buf, "\nThis might be a bug in periscope.\n\nRun with --debug to see a stack trace, and please consider opening a GitHub issue to report this occurrence.\n")
   156  	} else {
   157  		fmt.Fprintf(buf, "--------\n%s--------\n", i.stackTrace)
   158  	}
   159  	return buf.String()
   160  }
   161  
   162  func Internal(err error, message string) Interface {
   163  	return &internal{base: newBase(), message: strings.TrimSpace(message), err: err}
   164  }