github.com/biogo/biogo@v1.0.4/errors/errors.go (about)

     1  // Copyright ©2011-2013 The bíogo Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package errors supports generic rich error reporting.
     6  //
     7  // This package is deprecated. Since it was written much better
     8  // approaches have been developed.
     9  package errors
    10  
    11  import (
    12  	"bytes"
    13  	"fmt"
    14  	"runtime"
    15  	"strings"
    16  )
    17  
    18  // Type Error is the interface for rich error reporting supported by the
    19  // errors package.
    20  type Error interface {
    21  	// FileLine returns the file name and line number of caller
    22  	// stored at creation of the Error.
    23  	FileLine() (file string, line int)
    24  
    25  	// Trace returns a slice continuing the stack trace stored at
    26  	// creation of the Error.
    27  	Trace() (stack []*runtime.Func)
    28  
    29  	// Package returns the package name of the stored caller.
    30  	Package() string
    31  
    32  	// Function returns the function name of the stored caller.
    33  	Function() string
    34  
    35  	// Items returns any items retained by caller.
    36  	Items() []interface{}
    37  
    38  	// Tracef returns a formatted stack trace of the error
    39  	// extending depth frames into the stack, 0 indicates no limit.
    40  	Tracef(depth int) string
    41  	error
    42  }
    43  
    44  type errorBase struct {
    45  	*runtime.Func
    46  	pc      []uintptr
    47  	message string
    48  	items   []interface{}
    49  }
    50  
    51  // Make creates a new Error with message, storing information about the
    52  // caller stack frame skip levels above the caller and any item that may
    53  // be needed for handling the error. The number of frames stored is specified
    54  // by the depth parameter. If depth is zero, Make will panic.
    55  func Make(message string, skip, depth int, items ...interface{}) Error {
    56  	if depth == 0 {
    57  		panic("errors: zero trace depth")
    58  	}
    59  	err := &errorBase{
    60  		pc:      make([]uintptr, depth),
    61  		message: message,
    62  		items:   items,
    63  	}
    64  
    65  	var n int
    66  	if n = runtime.Callers(skip+2, err.pc); n > 0 {
    67  		err.Func = runtime.FuncForPC(err.pc[0])
    68  	}
    69  	err.pc = err.pc[:n]
    70  
    71  	return err
    72  }
    73  
    74  // Return the file name and line number of caller stored at creation of
    75  // the Error.
    76  func (err *errorBase) FileLine() (file string, line int) {
    77  	return err.Func.FileLine(err.pc[0])
    78  }
    79  
    80  // Return a slice contining the stack trace stored at creation of the Error.
    81  func (err *errorBase) Trace() (stack []*runtime.Func) {
    82  	stack = make([]*runtime.Func, len(err.pc))
    83  	for i, pc := range err.pc {
    84  		stack[i] = runtime.FuncForPC(pc)
    85  	}
    86  
    87  	return
    88  }
    89  
    90  // Return the package name of the stored caller.
    91  func (err *errorBase) Package() string {
    92  	caller := strings.Split(err.Func.Name(), ".")
    93  	return strings.Join(caller[0:len(caller)-1], ".")
    94  }
    95  
    96  // Return the function name of the stored caller.
    97  func (err *errorBase) Function() string {
    98  	caller := strings.Split(err.Func.Name(), ".")
    99  	return caller[len(caller)-1]
   100  }
   101  
   102  // Return any items retained by caller.
   103  func (err *errorBase) Items() []interface{} { return err.items }
   104  
   105  // A formatted stack trace of the error extending depth frames into the
   106  // stack, 0 indicates no limit.
   107  func (err *errorBase) Tracef(depth int) string {
   108  	var last, name string
   109  	b := &bytes.Buffer{}
   110  	fmt.Fprintf(b, "Trace: %s:\n", err.message)
   111  	for i, frame := range err.Trace() {
   112  		if depth > 0 && i >= depth {
   113  			break
   114  		}
   115  		file, line := frame.FileLine(err.pc[i])
   116  		if name = frame.Name(); name != last {
   117  			fmt.Fprintf(b, "\n %s:\n", frame.Name())
   118  		}
   119  		last = name
   120  		fmt.Fprintf(b, "\t%s#L=%d\n", file, line)
   121  	}
   122  
   123  	return string(b.Bytes())
   124  }
   125  
   126  // Satisfy the error interface.
   127  func (err *errorBase) Error() string {
   128  	return err.message
   129  }