github.com/eagleql/xray-core@v1.4.4/common/errors/errors.go (about)

     1  // Package errors is a drop-in replacement for Golang lib 'errors'.
     2  package errors // import "github.com/eagleql/xray-core/common/errors"
     3  
     4  import (
     5  	"os"
     6  	"reflect"
     7  	"strings"
     8  
     9  	"github.com/eagleql/xray-core/common/log"
    10  	"github.com/eagleql/xray-core/common/serial"
    11  )
    12  
    13  const trim = len("github.com/eagleql/xray-core/")
    14  
    15  type hasInnerError interface {
    16  	// Inner returns the underlying error of this one.
    17  	Inner() error
    18  }
    19  
    20  type hasSeverity interface {
    21  	Severity() log.Severity
    22  }
    23  
    24  // Error is an error object with underlying error.
    25  type Error struct {
    26  	pathObj  interface{}
    27  	prefix   []interface{}
    28  	message  []interface{}
    29  	inner    error
    30  	severity log.Severity
    31  }
    32  
    33  func (err *Error) WithPathObj(obj interface{}) *Error {
    34  	err.pathObj = obj
    35  	return err
    36  }
    37  
    38  func (err *Error) pkgPath() string {
    39  	if err.pathObj == nil {
    40  		return ""
    41  	}
    42  	path := reflect.TypeOf(err.pathObj).PkgPath()
    43  	if len(path) >= trim {
    44  		return path[trim:]
    45  	}
    46  	return path
    47  }
    48  
    49  // Error implements error.Error().
    50  func (err *Error) Error() string {
    51  	builder := strings.Builder{}
    52  	for _, prefix := range err.prefix {
    53  		builder.WriteByte('[')
    54  		builder.WriteString(serial.ToString(prefix))
    55  		builder.WriteString("] ")
    56  	}
    57  
    58  	path := err.pkgPath()
    59  	if len(path) > 0 {
    60  		builder.WriteString(path)
    61  		builder.WriteString(": ")
    62  	}
    63  
    64  	msg := serial.Concat(err.message...)
    65  	builder.WriteString(msg)
    66  
    67  	if err.inner != nil {
    68  		builder.WriteString(" > ")
    69  		builder.WriteString(err.inner.Error())
    70  	}
    71  
    72  	return builder.String()
    73  }
    74  
    75  // Inner implements hasInnerError.Inner()
    76  func (err *Error) Inner() error {
    77  	if err.inner == nil {
    78  		return nil
    79  	}
    80  	return err.inner
    81  }
    82  
    83  func (err *Error) Base(e error) *Error {
    84  	err.inner = e
    85  	return err
    86  }
    87  
    88  func (err *Error) atSeverity(s log.Severity) *Error {
    89  	err.severity = s
    90  	return err
    91  }
    92  
    93  func (err *Error) Severity() log.Severity {
    94  	if err.inner == nil {
    95  		return err.severity
    96  	}
    97  
    98  	if s, ok := err.inner.(hasSeverity); ok {
    99  		as := s.Severity()
   100  		if as < err.severity {
   101  			return as
   102  		}
   103  	}
   104  
   105  	return err.severity
   106  }
   107  
   108  // AtDebug sets the severity to debug.
   109  func (err *Error) AtDebug() *Error {
   110  	return err.atSeverity(log.Severity_Debug)
   111  }
   112  
   113  // AtInfo sets the severity to info.
   114  func (err *Error) AtInfo() *Error {
   115  	return err.atSeverity(log.Severity_Info)
   116  }
   117  
   118  // AtWarning sets the severity to warning.
   119  func (err *Error) AtWarning() *Error {
   120  	return err.atSeverity(log.Severity_Warning)
   121  }
   122  
   123  // AtError sets the severity to error.
   124  func (err *Error) AtError() *Error {
   125  	return err.atSeverity(log.Severity_Error)
   126  }
   127  
   128  // String returns the string representation of this error.
   129  func (err *Error) String() string {
   130  	return err.Error()
   131  }
   132  
   133  // WriteToLog writes current error into log.
   134  func (err *Error) WriteToLog(opts ...ExportOption) {
   135  	var holder ExportOptionHolder
   136  
   137  	for _, opt := range opts {
   138  		opt(&holder)
   139  	}
   140  
   141  	if holder.SessionID > 0 {
   142  		err.prefix = append(err.prefix, holder.SessionID)
   143  	}
   144  
   145  	log.Record(&log.GeneralMessage{
   146  		Severity: GetSeverity(err),
   147  		Content:  err,
   148  	})
   149  }
   150  
   151  type ExportOptionHolder struct {
   152  	SessionID uint32
   153  }
   154  
   155  type ExportOption func(*ExportOptionHolder)
   156  
   157  // New returns a new error object with message formed from given arguments.
   158  func New(msg ...interface{}) *Error {
   159  	return &Error{
   160  		message:  msg,
   161  		severity: log.Severity_Info,
   162  	}
   163  }
   164  
   165  // Cause returns the root cause of this error.
   166  func Cause(err error) error {
   167  	if err == nil {
   168  		return nil
   169  	}
   170  L:
   171  	for {
   172  		switch inner := err.(type) {
   173  		case hasInnerError:
   174  			if inner.Inner() == nil {
   175  				break L
   176  			}
   177  			err = inner.Inner()
   178  		case *os.PathError:
   179  			if inner.Err == nil {
   180  				break L
   181  			}
   182  			err = inner.Err
   183  		case *os.SyscallError:
   184  			if inner.Err == nil {
   185  				break L
   186  			}
   187  			err = inner.Err
   188  		default:
   189  			break L
   190  		}
   191  	}
   192  	return err
   193  }
   194  
   195  // GetSeverity returns the actual severity of the error, including inner errors.
   196  func GetSeverity(err error) log.Severity {
   197  	if s, ok := err.(hasSeverity); ok {
   198  		return s.Severity()
   199  	}
   200  	return log.Severity_Info
   201  }