github.com/xraypb/xray-core@v1.6.6/common/errors/errors.go (about)

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