ããã¯ããªã«ãããããŠæžãããã®ïŒ
Goã®ãšã©ãŒåŠçã«é¢ããæ å ±ãèŠãŠãããšxerrorsãšãããã®ãããåºãŠããã®ã§ã1床èŠãŠãããããªãšæããŸããŠã
xerrorsããã±ãŒãž
xerrorsããã±ãŒãžã¯ãGoã®ãšã©ãŒãã³ããªã³ã°ã®ããã®ããã±ãŒãžã§ãã
ãã®ããã±ãŒãžã®ææ¡å 容ã¯ããã¡ãã
Proposal: Go 2 Error Inspection
ãããæšæºããã±ãŒãžãerrorsã«åã蟌ãŸããã®ãGo 1.13ã®ããã§ãã
errors - The Go Programming Language
errorsããã±ãŒãžã«ã€ããŠã¯ã以åãã®ãšã³ããªã§è©ŠããŠã¿ãŸããã
xerrorsããã±ãŒãžãæã£ãŠããæ©èœã®ãã¡ãã»ãšãã©ã®ãã®ã¯errorsããã±ãŒãžã«å°å
¥ãããããã§ãã
ã§ããå°å
¥ãããªãã£ããã®ãããããã§ãã
ãããåŒã³åºãå ã®ãã¬ãŒã ãä¿åããæ©èœã®ããã§ããã
ä»åã¯ãxerrorsããã±ãŒãžã詊ããŠã¿ãããšæããŸãã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã§ãã
$ go version go version go1.16 linux/amd64
$ go mod init xerrors-example go: creating new go.mod: module xerrors-example
go.mod
module xerrors-example go 1.16 require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
go.sum
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
errorsãšxerrorsãæ¯ã¹ãªãã䜿ã£ãŠã¿ã
ã§ã¯ã䜿ã£ãŠãã£ãŠã¿ãŸããããæšæºããã±ãŒãžerrorsã®å ã«ãªã£ãã ããã£ãŠããšãŠããšãŠãè¯ã䌌ãŠããŸãã
errors - The Go Programming Language
以äžã®å¯Ÿæ¯ã«ãªãããã§ãã
errors.New
-xerros.New
fmt.Errorf
-xerrors.Errorf
errors.Is
-xerrors.Is
errors.As
-xerrors.As
errors.Unwrap
-xerrors.Unwrap
ãšã©ãŒã®åå ãå«ããã®ã«ã€ããŠã¯ãerrorsããã±ãŒãžã§ã¯ãªãfmtããã±ãŒãžã䜿ããŸããã
ãŸããerrorsãšå¯Ÿå¿å
ã®ãªããã®ãšããŠãxerrors.Opaque
ãšããã®ããããŸãã
ä»åã¯ãNew
ããã³Errorf
ãäžå¿ã«äœ¿ã£ãŠãããŸããããä»ã¯ã ãããåããããªã®ã§ã
äœæãããœãŒã¹ã³ãŒãã¯ããã¡ãã§ããåŒã³åºãäœçœ®ã®è¡šç€ºãããããšããã£ãŠãæåã¯è¡çªå·ä»ãã§è¡šç€ºããŠãããŸãã
$ cat -n main.go
1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "runtime" 7 8 "golang.org/x/xerrors" 9 ) 10 11 func main() { 12 fmt.Println("Case1:\n") 13 14 fmt.Printf("New error as errors: %v\n", errors.New("Oops!!")) 15 fmt.Println() 16 fmt.Printf("New error as errors: %+v\n", errors.New("Oops!!")) 17 18 printSeparator() 19 20 fmt.Printf("New error as xerrors: %v\n", xerrors.New("Oops!!")) 21 fmt.Println() 22 fmt.Printf("New error as xerrors: %+v\n", xerrors.New("Oops!!")) 23 24 fmt.Println("\nCase2:\n") 25 26 fmt.Printf("call error as errors: %+v\n", callErrors()) 27 28 printSeparator() 29 30 fmt.Printf("call error as xerrors: %+v\n", callXerrors()) 31 32 fmt.Println("\nCase3:\n") 33 34 fmt.Printf("wrap error as errors: %+v\n", wrapErrors()) 35 36 printSeparator() 37 38 fmt.Printf("wrap error as xerrors: %+v\n", wrapXerrors()) 39 40 fmt.Println("\nCase4:\n") 41 42 fmt.Printf("unwrap as errors: %+v\n", errors.Unwrap(wrapErrors())) 43 44 printSeparator() 45 46 fmt.Printf("unwrap as xerrors: %+v\n", xerrors.Unwrap(wrapXerrors())) 47 48 fmt.Println() 49 50 fmt.Printf("unwrap as xerrors / errors.Unwrap: %+v\n", errors.Unwrap(wrapXerrors())) 51 52 fmt.Println("\nCase5:\n") 53 54 fmt.Printf("wrap error as errors: %+v\n", wrapErrors()) 55 56 printSeparator() 57 58 fmt.Printf("wrap error as xerrors with opaque: %+v\n", xerrors.Opaque(wrapXerrors())) 59 60 fmt.Println("\nCase6:\n") 61 62 pc, file, line, ok := callRuntimeCaller0() 63 fmt.Printf("%v, %s, %d, %t\n", pc, file, line, ok) 64 65 printSeparator() 66 67 pc, file, line, ok = callRuntimeCaller1() 68 fmt.Printf("%v, %s, %d, %t\n", pc, file, line, ok) 69 70 printSeparator() 71 72 pcs := callRuntimeCallers0() 73 frames := runtime.CallersFrames(pcs) 74 75 for { 76 frame, more := frames.Next() 77 fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) 78 79 if !more { 80 break 81 } 82 } 83 84 printSeparator() 85 86 pcs = callRuntimeCallers1() 87 frames = runtime.CallersFrames(pcs) 88 89 for { 90 frame, more := frames.Next() 91 fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) 92 93 if !more { 94 break 95 } 96 } 97 98 printSeparator() 99 100 pcs = wrapCallRuntimeCaller1() 101 frames = runtime.CallersFrames(pcs) 102 103 for { 104 frame, more := frames.Next() 105 fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) 106 107 if !more { 108 break 109 } 110 } 111 } 112 113 func printSeparator() { 114 fmt.Println() 115 fmt.Println("======") 116 fmt.Println() 117 } 118 119 func causeErrorUseErrors() error { 120 return errors.New("Oops!!") 121 } 122 123 func callErrors() error { 124 return causeErrorUseErrors() 125 } 126 127 func wrapErrors() error { 128 return fmt.Errorf("Wrap Error!! cause: %w", causeErrorUseErrors()) 129 } 130 131 func causeErrorUseXerrors() error { 132 return xerrors.New("Oops!!") 133 } 134 135 func callXerrors() error { 136 return causeErrorUseXerrors() 137 } 138 139 func wrapXerrors() error { 140 return xerrors.Errorf("Wrap Error!! cause: %w", causeErrorUseXerrors()) 141 } 142 143 func callRuntimeCaller0() (uintptr, string, int, bool) { 144 return runtime.Caller(0) 145 } 146 147 func callRuntimeCaller1() (uintptr, string, int, bool) { 148 return runtime.Caller(1) 149 } 150 151 func callRuntimeCallers0() []uintptr { 152 var pcs [3]uintptr 153 runtime.Callers(0, pcs[:]) 154 return pcs[:] 155 } 156 157 func callRuntimeCallers1() []uintptr { 158 var pcs [3]uintptr 159 runtime.Callers(1, pcs[:]) 160 return pcs[:] 161 } 162 163 func wrapCallRuntimeCaller1() []uintptr { 164 return callRuntimeCallers1() 165 }
å®è¡ã¯ããã¡ãã§ã
$ go run main.go
é¢é£ãããœãŒã¹ã³ãŒãã®æç²ãšãå®è¡çµæã䜿ã£ãŠæžããŠããŸãã
%+v
ãšåŒã³åºãå
ã®è¡šç€º
æåã¯ãã¡ããNew
颿°ã䜿ã£ãŠããšã©ãŒãäœæããŸãã
12 fmt.Println("Case1:\n") 13 14 fmt.Printf("New error as errors: %v\n", errors.New("Oops!!")) 15 fmt.Println() 16 fmt.Printf("New error as errors: %+v\n", errors.New("Oops!!")) 17 18 printSeparator() 19 20 fmt.Printf("New error as xerrors: %v\n", xerrors.New("Oops!!")) 21 fmt.Println() 22 fmt.Printf("New error as xerrors: %+v\n", xerrors.New("Oops!!"))
å®è¡çµæã
Case1: New error as errors: Oops!! New error as errors: Oops!! ====== New error as xerrors: Oops!! New error as xerrors: Oops!!: main.main /path/to/main.go:22
xerrors.New
ã䜿ãããã€ãšã©ãŒè¡šç€ºã®æžåŒã«%+v
ãæå®ããå Žåã«ãã¡ã€ã«åãšè¡çªå·ã衚瀺ãããŸããã
fmt.Printf("New error as xerrors: %+v\n", xerrors.New("Oops!!"))
errors.New
ã®æ¹ã¯ããšã©ãŒã®æåå衚瀺ã®ã¿ã§ãã
%+v
ã®æå³ã¯ããã£ãŒã«ããå ãããã®ã§ãã
%v the value in a default format when printing structs, the plus flag (%+v) adds field names
fmt - The Go Programming Language
ãœãŒã¹ã³ãŒããèŠããšãFrame
ãåºåããŠããããšã«ãªããŸããã
https://github.com/golang/xerrors/blob/5ec99f83aff198f5fbd629d6c8d8eb38a04218ca/errors.go#L12
ãããxerrorsã䜿ã£ãæã«ããã¬ãŒã ãšåŒã°ããŠãããã®ã®ããã§ãã
颿°åŒã³åºããæãã§ã¿ã
次ã¯ãNew
颿°ãšæšæºåºåã®éã«ã颿°åŒã³åºããæãã§ã¿ãŸãããã
24 fmt.Println("\nCase2:\n") 25 26 fmt.Printf("call error as errors: %+v\n", callErrors()) 27 28 printSeparator() 29 30 fmt.Printf("call error as xerrors: %+v\n", callXerrors())
åŒã³åºãå ã®é¢æ°ã
119 func causeErrorUseErrors() error { 120 return errors.New("Oops!!") 121 } 122 123 func callErrors() error { 124 return causeErrorUseErrors() 125 } ãçç¥ã 131 func causeErrorUseXerrors() error { 132 return xerrors.New("Oops!!") 133 } 134 135 func callXerrors() error { 136 return causeErrorUseXerrors() 137 }
å®è¡çµæã
Case2: call error as errors: Oops!! ====== call error as xerrors: Oops!!: main.causeErrorUseXerrors /path/to/main.go:132
ã©ããããšã©ãŒãçæããããšãããŸã§ã®ã³ãŒã«ã¹ã¿ãã¯ã衚瀺ããããããªãã®ã§ã¯ãªãããã§ãã
ããã«è¡šç€ºãããŠããã®ã¯ãxerrors.New
ãåŒã³åºããå Žæãã®ãã®ã§ããã
ãšã©ãŒãã©ããããŠã¿ã
次ã¯ããšã©ãŒãã©ããããŠã¿ãŸããããfmt.Errorf
ããã³xerrors.Errorf
ãšãæžåŒæååã®%w
ã䜿ããŸãã
32 fmt.Println("\nCase3:\n") 33 34 fmt.Printf("wrap error as errors: %+v\n", wrapErrors()) 35 36 printSeparator() 37 38 fmt.Printf("wrap error as xerrors: %+v\n", wrapXerrors())
åŒã³åºãå ã
119 func causeErrorUseErrors() error { 120 return errors.New("Oops!!") 121 } 122 ãçç¥ã 126 127 func wrapErrors() error { 128 return fmt.Errorf("Wrap Error!! cause: %w", causeErrorUseErrors()) 129 } ãçç¥ã 131 func causeErrorUseXerrors() error { 132 return xerrors.New("Oops!!") 133 } 134 ãçç¥ã 138 139 func wrapXerrors() error { 140 return xerrors.Errorf("Wrap Error!! cause: %w", causeErrorUseXerrors()) 141 }
çµæã
Case3: wrap error as errors: Wrap Error!! cause: Oops!! ====== wrap error as xerrors: Wrap Error!! cause: main.wrapXerrors /path/to/main.go:140 - Oops!!: main.causeErrorUseXerrors /path/to/main.go:132
xerrors.Errorf
ã®æ¹ã¯ã%w
ã䜿ã£ãŠãã¹ããããåã®ãšã©ãŒãå«ããŠè¡šç€ºãããŠããŸãã
ãã®ã²ãšã€åã®çµæïŒåçŽã«ãšã©ãŒã颿°åŒã³åºãã§å
ãã å ŽåïŒã§ã¯ã³ãŒã«ã¹ã¿ãã¯ãå¢ããªãã£ãããšããèãããšã
ä»ã®èšèªã§ããèŠããããªé¢æ°åŒã³åºãã®ã³ãŒã«ã¹ã¿ãã¯ãåçŸããããã°ãååŒã³åºãããšã«ãšã©ãŒãã©ããããŠãã
å¿
èŠãããããã§ããã
UnwrapããŠã¿ã
ãã¹ãããããšã©ãŒãUnwrapããŠã¿ãŸãããã
40 fmt.Println("\nCase4:\n") 41 42 fmt.Printf("unwrap as errors: %+v\n", errors.Unwrap(wrapErrors())) 43 44 printSeparator() 45 46 fmt.Printf("unwrap as xerrors: %+v\n", xerrors.Unwrap(wrapXerrors())) 47 48 fmt.Println() 49 50 fmt.Printf("unwrap as xerrors / errors.Unwrap: %+v\n", errors.Unwrap(wrapXerrors()))
ãšã©ãŒã®äœæã«äœ¿ã£ãŠãã颿°ã¯ãå ã»ã©ãšåãã§ããã
çµæã
Case4: unwrap as errors: Oops!! ====== unwrap as xerrors: Oops!!: main.causeErrorUseXerrors /path/to/main.go:132 unwrap as xerrors / errors.Unwrap: Oops!!: main.causeErrorUseXerrors /path/to/main.go:132
xerrorsã®æ¹ã¯ãUnwrapããŠãåŒã³åºãå
ã®ãã¬ãŒã ã衚瀺ãããŸãããŸããxerrorsã§äœæãããšã©ãŒãerrorsã®æ¹ã§Unwrapããããšã
ã§ããŸããã
xerrors.Opaqueã䜿ã£ãŠã¿ã
xerrors.Opaque
ã䜿ã£ãŠã¿ãŸãããã
52 fmt.Println("\nCase5:\n") 53 54 fmt.Printf("wrap error as errors: %+v\n", wrapErrors()) 55 56 printSeparator() 57 58 fmt.Printf("wrap error as xerrors with opaque: %+v\n", xerrors.Opaque(wrapXerrors()))
ãã¡ãã䜿ããšãxerrorsã䜿ã£ãå Žåã§ãåŒã³åºãå ã®ãã¬ãŒã ãåºãªããªããŸãã
Case5: wrap error as errors: Wrap Error!! cause: Oops!! ====== wrap error as xerrors with opaque: Wrap Error!! cause: Oops!!
ã€ãŸããerrorsã䜿ã£ãæãšåãã«ãªããŸãããããã¹ãããããšã©ãŒã¯ä¿æããŠããããã§ãã
ããããããªãšããã§ãããããã ãããé°å²æ°ã¯ããã£ãæ°ãããŸãã
åŒã³åºãå ãã¬ãŒã ã®ååŸæ¹æ³
ãšããã§ãxerrorsã¯ã©ããã£ãŠåŒã³åºãå ã®ãã¬ãŒã ãååŸããŠãããã§ããããã
ãã¡ãã®ããã§ãã
https://github.com/golang/xerrors/blob/5ec99f83aff198f5fbd629d6c8d8eb38a04218ca/frame.go#L24
runtimeããã±ãŒãžã䜿ã£ãŠããããã§ããã
runtime - The Go Programming Language
ãŸããä»ã®èšèªã§ã®ã³ãŒã«ã¹ã¿ãã¯ã®ããã«ãªããªãã®ã¯ãæååã«å€æããŠããæã«1è¡åããæ®ããŠããªãããã¿ããã§ããã
https://github.com/golang/xerrors/blob/5ec99f83aff198f5fbd629d6c8d8eb38a04218ca/frame.go#L48
https://github.com/golang/xerrors/blob/5ec99f83aff198f5fbd629d6c8d8eb38a04218ca/frame.go#L31-L41
xerrorsã䜿ã£ãŠããã®ã¯runtime.Callers
ã§ããã
https://github.com/golang/xerrors/blob/5ec99f83aff198f5fbd629d6c8d8eb38a04218ca/frame.go#L24
ãŸãã¯runtime.Caller
ã䜿ã£ãŠã¿ãŸãããã
60 fmt.Println("\nCase6:\n") 61 62 pc, file, line, ok := callRuntimeCaller0() 63 fmt.Printf("%v, %s, %d, %t\n", pc, file, line, ok) 64 65 printSeparator() 66 67 pc, file, line, ok = callRuntimeCaller1() 68 fmt.Printf("%v, %s, %d, %t\n", pc, file, line, ok)
ãããããruntime.Caller
ã«0ãš1ãæž¡ããŠããŸãã
143 func callRuntimeCaller0() (uintptr, string, int, bool) { 144 return runtime.Caller(0) 145 } 146 147 func callRuntimeCaller1() (uintptr, string, int, bool) { 148 return runtime.Caller(1) 149 }
å®è¡çµæã
Case6: 4856742, /path/to/main.go, 144, true ====== 4857125, /path/to/main.go, 67, true
0ã®æ¹ã¯ããŸãã«ãã®äœçœ®ã衚瀺ããŠããŸãã
143 func callRuntimeCaller0() (uintptr, string, int, bool) { 144 return runtime.Caller(0) 145 }
察ããŠ1ã®æ¹ã¯ãåŒã³åºãå ã®ã³ãŒãã®äœçœ®ã衚瀺ããŠããŸãã
67 pc, file, line, ok = callRuntimeCaller1()
ã€ãŸããruntime.Caller
ã«äžããå€ã¯ãã©ãã ãåŒã³åºãå
ãŸã§ã®ãã¬ãŒã ãã¹ãããããããæå³ããŸãã
次ã«runtime.Callers
ã䜿ã£ãŠã¿ãŸãã
Packages runtime / func Callers
ãã¡ãã®ç¬¬1åŒæ°ã¯ãã©ãã ããã¬ãŒã ãã¹ããããããã§ãããããŠã第2åŒæ°ã«ãã¬ãŒã ãä¿åããŸãã
ãã®çµæãšruntime.CallersFrames
ãçµã¿åãããããšã§ãã¹ã¿ãã¯ãã¬ãŒã¹ãåçŸã§ããŸãã
Package runtime / func CallersFrames
72 pcs := callRuntimeCallers0() 73 frames := runtime.CallersFrames(pcs) 74 75 for { 76 frame, more := frames.Next() 77 fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) 78 79 if !more { 80 break 81 } 82 } 83 84 printSeparator() 85 86 pcs = callRuntimeCallers1() 87 frames = runtime.CallersFrames(pcs) 88 89 for { 90 frame, more := frames.Next() 91 fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) 92 93 if !more { 94 break 95 } 96 }
ãã ãã©ã®ãããã®æ°ã®ãã¬ãŒã ãååŸãããã¯ãåºå®ã§æ±ºããªããšãããªãããã§ããã©ãã
151 func callRuntimeCallers0() []uintptr { 152 var pcs [3]uintptr 153 runtime.Callers(0, pcs[:]) 154 return pcs[:] 155 } 156 157 func callRuntimeCallers1() []uintptr { 158 var pcs [3]uintptr 159 runtime.Callers(1, pcs[:]) 160 return pcs[:] 161 }
çµæã
runtime.Callers(/usr/lib/go-1.16/src/runtime/extern.go:229) main.callRuntimeCallers0(/path/to/main.go:153) main.main(/path/to/main.go:72) ====== main.callRuntimeCallers1(/path/to/main.go:159) main.main(/path/to/main.go:86) runtime.main(/usr/lib/go-1.16/src/runtime/proc.go:225)
runtime.Callers
ã®ç¬¬1åŒæ°ã0ã«ãããšãruntime.Callers
èªèº«ãå«ãŸããŸããâŠãã©ããŸã§ã¹ãããããããæå®ããã®ã¯ã
éèŠãªæ§åã§ãã
ãã¬ãŒã ãååŸãããŸã§ã«ãããã«é¢æ°åŒã³åºããæãã§ã¿ãŸãããã
100 pcs = wrapCallRuntimeCaller1() 101 frames = runtime.CallersFrames(pcs) 102 103 for { 104 frame, more := frames.Next() 105 fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) 106 107 if !more { 108 break 109 } 110 }
ãããªæãã§ããã
157 func callRuntimeCallers1() []uintptr { 158 var pcs [3]uintptr 159 runtime.Callers(1, pcs[:]) 160 return pcs[:] 161 } 162 163 func wrapCallRuntimeCaller1() []uintptr { 164 return callRuntimeCallers1() 165 }
çµæãããã£ãœããªã£ãŠããŸããã
main.callRuntimeCallers1(/path/to/main.go:159) main.wrapCallRuntimeCaller1(/path/to/main.go:164) main.main(/path/to/main.go:100)
ãã®ãããã®é°å²æ°ã¯ããã£ãæ°ãããŸãã
ãšã¯ãããxerrorsã®æ¹ãä¿æããŠãããã¬ãŒã ã3ã€åã ãã®ããã§ããã
https://github.com/golang/xerrors/blob/5ec99f83aff198f5fbd629d6c8d8eb38a04218ca/frame.go#L16
ããããããããã¹ã¿ãã¯ãã¬ãŒã¹ã®ãããªãã®ã«é Œããããªèšèªã§ã¯ãªãã®ã§ããããã
ãã®ãããã®æ å ±ã¯ãåèçšåºŠã«èŠããŠãããããªãšæããŸãã
ãªãã±
æåŸã«ãè¡çªå·ãªãã®ãœãŒã¹ã³ãŒããèŒããŠãããŸãããã
main.go
package main import ( "errors" "fmt" "runtime" "golang.org/x/xerrors" ) func main() { fmt.Println("Case1:\n") fmt.Printf("New error as errors: %v\n", errors.New("Oops!!")) fmt.Println() fmt.Printf("New error as errors: %+v\n", errors.New("Oops!!")) printSeparator() fmt.Printf("New error as xerrors: %v\n", xerrors.New("Oops!!")) fmt.Println() fmt.Printf("New error as xerrors: %+v\n", xerrors.New("Oops!!")) fmt.Println("\nCase2:\n") fmt.Printf("call error as errors: %+v\n", callErrors()) printSeparator() fmt.Printf("call error as xerrors: %+v\n", callXerrors()) fmt.Println("\nCase3:\n") fmt.Printf("wrap error as errors: %+v\n", wrapErrors()) printSeparator() fmt.Printf("wrap error as xerrors: %+v\n", wrapXerrors()) fmt.Println("\nCase4:\n") fmt.Printf("unwrap as errors: %+v\n", errors.Unwrap(wrapErrors())) printSeparator() fmt.Printf("unwrap as xerrors: %+v\n", xerrors.Unwrap(wrapXerrors())) fmt.Println() fmt.Printf("unwrap as xerrors / errors.Unwrap: %+v\n", errors.Unwrap(wrapXerrors())) fmt.Println("\nCase5:\n") fmt.Printf("wrap error as errors: %+v\n", wrapErrors()) printSeparator() fmt.Printf("wrap error as xerrors with opaque: %+v\n", xerrors.Opaque(wrapXerrors())) fmt.Println("\nCase6:\n") pc, file, line, ok := callRuntimeCaller0() fmt.Printf("%v, %s, %d, %t\n", pc, file, line, ok) printSeparator() pc, file, line, ok = callRuntimeCaller1() fmt.Printf("%v, %s, %d, %t\n", pc, file, line, ok) printSeparator() pcs := callRuntimeCallers0() frames := runtime.CallersFrames(pcs) for { frame, more := frames.Next() fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) if !more { break } } printSeparator() pcs = callRuntimeCallers1() frames = runtime.CallersFrames(pcs) for { frame, more := frames.Next() fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) if !more { break } } printSeparator() pcs = wrapCallRuntimeCaller1() frames = runtime.CallersFrames(pcs) for { frame, more := frames.Next() fmt.Printf(" %s(%s:%d)\n", frame.Function, frame.File, frame.Line) if !more { break } } } func printSeparator() { fmt.Println() fmt.Println("======") fmt.Println() } func causeErrorUseErrors() error { return errors.New("Oops!!") } func callErrors() error { return causeErrorUseErrors() } func wrapErrors() error { return fmt.Errorf("Wrap Error!! cause: %w", causeErrorUseErrors()) } func causeErrorUseXerrors() error { return xerrors.New("Oops!!") } func callXerrors() error { return causeErrorUseXerrors() } func wrapXerrors() error { return xerrors.Errorf("Wrap Error!! cause: %w", causeErrorUseXerrors()) } func callRuntimeCaller0() (uintptr, string, int, bool) { return runtime.Caller(0) } func callRuntimeCaller1() (uintptr, string, int, bool) { return runtime.Caller(1) } func callRuntimeCallers0() []uintptr { var pcs [3]uintptr runtime.Callers(0, pcs[:]) return pcs[:] } func callRuntimeCallers1() []uintptr { var pcs [3]uintptr runtime.Callers(1, pcs[:]) return pcs[:] } func wrapCallRuntimeCaller1() []uintptr { return callRuntimeCallers1() }