github.com/eframework-cn/EP.GO.UTIL@v1.0.0/xrun/xrun.go (about) 1 //-----------------------------------------------------------------------// 2 // GNU GENERAL PUBLIC LICENSE // 3 // Version 2, June 1991 // 4 // // 5 // Copyright (C) EFramework, https://eframework.cn, All rights reserved. // 6 // Everyone is permitted to copy and distribute verbatim copies // 7 // of this license document, but changing it is not allowed. // 8 // SEE LICENSE.md FOR MORE DETAILS. // 9 //-----------------------------------------------------------------------// 10 11 // 协程上层封装,包括异常捕捉、闪退重启、消耗时间、调用堆栈等功能. 12 package xrun 13 14 import ( 15 "bytes" 16 "fmt" 17 "os" 18 "reflect" 19 "runtime" 20 21 "github.com/eframework-cn/EP.GO.UTIL/xfs" 22 "github.com/eframework-cn/EP.GO.UTIL/xlog" 23 "github.com/eframework-cn/EP.GO.UTIL/xtime" 24 ) 25 26 const ( 27 UNKONWN_SOURCE = "[?]" 28 ) 29 30 // 获取函数调用堆栈信息 31 // stack: 堆栈层级 32 // fullpath: 全路径 33 func Caller(stack int, fullpath bool) string { 34 if pc, file, line, ok := runtime.Caller(stack + 1); ok { 35 if fullpath { 36 return fmt.Sprintf("[%s:%d (0x%v)]", file, line, pc) 37 } else { 38 return fmt.Sprintf("[%s:%d (0x%v)]", runtime.FuncForPC(pc).Name(), line, pc) 39 } 40 } 41 return UNKONWN_SOURCE 42 } 43 44 // 获取错误堆栈信息 45 // stack: 堆栈层级 46 // err: 错误信息 47 func StackTrace(stack int, err interface{}) (string, int) { 48 buf := new(bytes.Buffer) 49 fmt.Fprintf(buf, "%v\n", err) 50 start := stack + 1 51 count := stack 52 fmt.Fprintf(buf, " skip %v\n", stack) 53 for i := start; ; i++ { 54 line := Caller(i, true) 55 if line == UNKONWN_SOURCE { 56 break 57 } 58 count++ 59 fmt.Fprintf(buf, " %v\n", line) 60 } 61 return buf.String(), count 62 } 63 64 // 计算函数执行消耗的时间,在起始处调用defer Elapse(stack)() 65 // stack: 堆栈层级(0为当前层) 66 func Elapse(stack int, callback ...func()) func() { 67 start := xtime.GetMillisecond() 68 return func() { 69 end := xtime.GetMillisecond() 70 elapse := end - start 71 if stack < 0 { 72 stack = 0 73 } 74 caller := Caller(stack+1, false) 75 xlog.Notice("xrun.Elapse%v: start-%v, end-%v, elapsed-%vms", caller, start, end, elapse) 76 if len(callback) == 1 { 77 callback[0]() 78 } 79 } 80 } 81 82 func doCaught(exit bool, stack int, handler ...func(string, int)) { 83 if err := recover(); err != nil { 84 str, count := StackTrace(stack+1, err) 85 fname := fmt.Sprintf("log/crash/%v.log", xtime.Format(xtime.GetTimestamp(), xtime.STRING_TIME_FORMAT_FILE)) 86 xfs.PathExist(xfs.Directory(fname), true) 87 xfs.WriteString(fname, str) 88 xlog.Critical(str) 89 if len(handler) == 1 { 90 handler[0](str, count) 91 } 92 if exit { 93 xlog.Critical("exit now!") 94 xlog.Close() 95 os.Exit(1) 96 } 97 } 98 } 99 100 // 捕捉goroutine的异常 101 // exit: 是否结束进程 102 // handler: 回调 103 func Caught(exit bool, handler ...func(string, int)) { 104 doCaught(exit, 0, handler...) 105 } 106 107 // 协程封装器(panic不会引起crash,recover后该goroutine结束) 108 func Exec(fun interface{}, params ...interface{}) { 109 defer Caught(false) 110 vf := reflect.ValueOf(fun) 111 vps := make([]reflect.Value, len(params)) 112 for i := 0; i < len(params); i++ { 113 param := params[i] 114 vps[i] = reflect.ValueOf(param) 115 } 116 vf.Call(vps) 117 } 118 119 func doRun(fun interface{}, stack int, params ...interface{}) { 120 defer doCaught(false, stack, func(s string, i int) { 121 doRun(fun, i, params...) 122 }) 123 vf := reflect.ValueOf(fun) 124 vps := make([]reflect.Value, len(params)) 125 for i := 0; i < len(params); i++ { 126 vps[i] = reflect.ValueOf(params[i]) 127 } 128 vf.Call(vps) 129 } 130 131 // 协程封装器(panic不会引起crash,recover后重启该goroutine) 132 func Run(fun interface{}, params ...interface{}) { 133 doRun(fun, 0, params...) 134 }