github.com/binbinly/pkg@v0.0.11-0.20240321014439-f4fbf666eb0f/util/runtime.go (about)

     1  package util
     2  
     3  import (
     4  	"log"
     5  	"os"
     6  	"os/signal"
     7  	"path/filepath"
     8  	"runtime"
     9  	"syscall"
    10  	_ "unsafe"
    11  )
    12  
    13  var (
    14  	StackTraceBufferSize = 4 << 10
    15  )
    16  
    17  // RecoveryCallback 自定义恢复信息回调
    18  type RecoveryCallback func(err any, trace []byte)
    19  
    20  // CallPath 运行时路径, 编译目录
    21  // 假如: mklink E:\tmp\linkapp.exe D:\Fufu\Test\abc\app.exe
    22  // 执行: E:\tmp\linkapp.exe
    23  // CallPath: E:\Go\src\github.com\fufuok\utils\tmp\osext
    24  func CallPath() string {
    25  	_, filename, _, ok := runtime.Caller(1)
    26  	if ok {
    27  		return filepath.Clean(filepath.Dir(filename))
    28  	}
    29  
    30  	return RunPath()
    31  }
    32  
    33  // RunPath 实际程序所在目录
    34  // RunPath: E:\tmp
    35  func RunPath() string {
    36  	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    37  	if err != nil {
    38  		// 调用时工作目录
    39  		dir, _ = os.Getwd()
    40  		return dir
    41  	}
    42  
    43  	return dir
    44  }
    45  
    46  // Executable 当前执行程序绝对路径
    47  // true 时返回解析符号链接后的绝对路径
    48  // Excutable: E:\tmp\linkapp.exe
    49  // Excutable(true): D:\Fufu\Test\abc\app.exe
    50  func Executable(evalSymlinks ...bool) string {
    51  	exe, _ := os.Executable()
    52  	if len(evalSymlinks) > 0 && evalSymlinks[0] {
    53  		exe, _ = filepath.EvalSymlinks(exe)
    54  	}
    55  
    56  	return filepath.Clean(exe)
    57  }
    58  
    59  // ExecutableDir 当前执行程序所在目录
    60  // true 时返回解析符号链接后的目录
    61  // ExcutableDir: E:\tmp
    62  // ExcutableDir(true): D:\Fufu\Test\abc
    63  func ExecutableDir(evalSymlinks ...bool) string {
    64  	return filepath.Dir(Executable(evalSymlinks...))
    65  }
    66  
    67  // Recover 从 panic 中恢复并记录堆栈信息
    68  func Recover(cb ...RecoveryCallback) {
    69  	if err := recover(); err != nil {
    70  		buf := make([]byte, StackTraceBufferSize)
    71  		buf = buf[:runtime.Stack(buf, false)]
    72  		if len(cb) > 0 && cb[0] != nil {
    73  			cb[0](err, buf)
    74  			return
    75  		}
    76  		log.Printf("Recovery: %v\n--- Traceback:\n%v\n", err, string(buf))
    77  	}
    78  }
    79  
    80  // SafeGo 带 Recover 的 goroutine 运行
    81  func SafeGo(fn func(), cb ...RecoveryCallback) {
    82  	defer Recover(cb...)
    83  	fn()
    84  }
    85  
    86  // WaitSignal 等待系统信号
    87  // 默认捕获退出类信息
    88  func WaitSignal(sig ...os.Signal) os.Signal {
    89  	if len(sig) == 0 {
    90  		sig = []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT}
    91  	}
    92  	ch := make(chan os.Signal, 1)
    93  	signal.Notify(ch, sig...)
    94  	return <-ch
    95  }
    96  
    97  // FastRand 随机数
    98  //
    99  //go:linkname FastRand runtime.fastrand
   100  func FastRand() uint32
   101  
   102  // FastRandn 等同于 FastRand() % n, 但更快
   103  // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
   104  //
   105  //go:linkname FastRandn runtime.fastrandn
   106  func FastRandn(n uint32) uint32
   107  
   108  // CPUTicks CPU 时钟周期, 更高精度 (云服务器做伪随机数种子时慎用)
   109  //
   110  //go:linkname CPUTicks runtime.cputicks
   111  func CPUTicks() int64
   112  
   113  // NanoTime 返回当前时间 (以纳秒为单位)
   114  //
   115  //go:linkname NanoTime runtime.nanotime
   116  func NanoTime() int64