github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmn/debug/debug_on.go (about) 1 //go:build debug 2 3 // Package provides debug utilities 4 /* 5 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 6 */ 7 package debug 8 9 import ( 10 "bytes" 11 "expvar" 12 "flag" 13 "fmt" 14 "net/http" 15 "net/http/pprof" 16 "os" 17 "path/filepath" 18 "reflect" 19 "runtime" 20 "strings" 21 "sync" 22 23 "github.com/NVIDIA/aistore/cmn/nlog" 24 ) 25 26 func ON() bool { return true } 27 28 func Infof(f string, a ...any) { 29 nlog.InfoDepth(1, fmt.Sprintf("[DEBUG] "+f, a...)) 30 } 31 32 func Func(f func()) { f() } 33 34 func _panic(a ...any) { 35 msg := "DEBUG PANIC: " 36 if len(a) > 0 { 37 msg += fmt.Sprint(a...) + ": " 38 } 39 buffer := bytes.NewBuffer(make([]byte, 0, 1024)) 40 buffer.WriteString(msg) 41 for i := 2; i < 9; i++ { 42 if _, file, line, ok := runtime.Caller(i); !ok { 43 break 44 } else { 45 // alternatively, the entire stack w/ full pathnames 46 if !strings.Contains(file, "aistore") { 47 break 48 } 49 f := filepath.Base(file) 50 if l := len(f); l > 3 { 51 f = f[:l-3] 52 } 53 if buffer.Len() > len(msg) { 54 buffer.WriteString(" <- ") 55 } 56 fmt.Fprintf(buffer, "%s:%d", f, line) 57 } 58 } 59 if flag.Parsed() { 60 nlog.Errorln(buffer.String()) 61 nlog.Flush(nlog.ActExit) 62 } else { 63 fmt.Fprintln(os.Stderr, buffer.String()) 64 } 65 66 if !nlog.Stopping() { // no panicking when stopping 67 panic(msg) 68 } 69 } 70 71 func Assert(cond bool, a ...any) { 72 if !cond { 73 _panic(a...) 74 } 75 } 76 77 func AssertFunc(f func() bool, a ...any) { 78 if !f() { 79 _panic(a...) 80 } 81 } 82 83 func AssertNoErr(err error) { 84 if err != nil { 85 _panic(err) 86 } 87 } 88 89 func Assertf(cond bool, f string, a ...any) { 90 if !cond { 91 msg := fmt.Sprintf(f, a...) 92 _panic(msg) 93 } 94 } 95 96 func AssertMutexLocked(m *sync.Mutex) { 97 state := reflect.ValueOf(m).Elem().FieldByName("state") 98 Assert(state.Int()&1 == 1, "Mutex not Locked") 99 } 100 101 func AssertRWMutexLocked(m *sync.RWMutex) { 102 state := reflect.ValueOf(m).Elem().FieldByName("w").FieldByName("state") 103 Assert(state.Int()&1 == 1, "RWMutex not Locked") 104 } 105 106 func AssertRWMutexRLocked(m *sync.RWMutex) { 107 const maxReaders = 1 << 30 // Taken from `sync/rwmutex.go`. 108 rc := reflect.ValueOf(m).Elem().FieldByName("readerCount").Int() 109 // NOTE: As it's generally true that `rc > 0` the problem arises when writer 110 // tries to lock the mutex. The writer announces it by manipulating `rc` 111 // (to be specific, decreases `rc` by `maxReaders`). Therefore, to check if 112 // there are any readers still holding lock we need to check both cases. 113 Assert(rc > 0 || (0 > rc && rc > -maxReaders), "RWMutex not RLocked") 114 } 115 116 func AssertNotPstr(a any) { 117 if _, ok := a.(*string); ok { 118 _panic(fmt.Errorf("invalid usage: %v (%T)", a, a)) 119 } 120 } 121 122 func FailTypeCast(a any) { 123 val := fmt.Sprint(a) 124 if len(val) < 32 { 125 _panic(fmt.Errorf("unexpected type %s: (%T)", val, a)) 126 } else { 127 _panic(fmt.Errorf("unexpected type (%T)", a)) 128 } 129 } 130 131 func Handlers() map[string]http.HandlerFunc { 132 return map[string]http.HandlerFunc{ 133 "/debug/vars": expvar.Handler().ServeHTTP, 134 "/debug/pprof/": pprof.Index, 135 "/debug/pprof/cmdline": pprof.Cmdline, 136 "/debug/pprof/profile": pprof.Profile, 137 "/debug/pprof/symbol": pprof.Symbol, 138 "/debug/pprof/block": pprof.Handler("block").ServeHTTP, 139 "/debug/pprof/heap": pprof.Handler("heap").ServeHTTP, 140 "/debug/pprof/goroutine": pprof.Handler("goroutine").ServeHTTP, 141 "/debug/pprof/threadcreate": pprof.Handler("threadcreate").ServeHTTP, 142 } 143 } 144 145 func fatalMsg(f string, v ...any) { 146 s := fmt.Sprintf(f, v...) 147 if s == "" || s[len(s)-1] != '\n' { 148 fmt.Fprintln(os.Stderr, s) 149 } else { 150 fmt.Fprint(os.Stderr, s) 151 } 152 os.Exit(1) 153 }