errors.go 3.8 KB

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