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  }