github.com/zeebo/mon@v0.0.0-20211012163247-13d39bdb54fa/time.go (about) 1 // +build !nomon 2 3 package mon 4 5 import ( 6 "strings" 7 "sync/atomic" 8 _ "unsafe" 9 10 "github.com/zeebo/this" 11 ) 12 13 //go:linkname nanotime runtime.nanotime 14 func nanotime() (mono int64) 15 16 // Thunk is a type that allows one to get the benefits of Time without having to 17 // compute the caller every time it's called. Zero values are valid. 18 type Thunk struct { 19 val atomic.Value 20 } 21 22 // Time returns a Timer where the name is chosen the first time by the caller. Don't 23 // use the same Thunk from different functions/methods. 24 func (t *Thunk) Start() Timer { 25 name := t.val.Load() 26 if name == nil { 27 name = this.ThisN(1) 28 t.val.Store(name) 29 } 30 return StartNamed(name.(string)) 31 } 32 33 // Start returns a Timer using the calling function for the name. 34 func Start() (t Timer) { 35 return StartNamed(this.ThisN(1)) 36 } 37 38 // StartNamed returns a Timer that records a duration when its Done method is called. 39 func StartNamed(name string) Timer { 40 return Timer{ 41 now: nanotime(), 42 state: GetState(name), 43 } 44 } 45 46 // Timer keeps track of the state necessary to record timing info. 47 type Timer struct { 48 now int64 49 state *State 50 } 51 52 // Stop records the timing info. 53 func (r Timer) Stop(err *error) { 54 kind := "" 55 if err != nil { 56 kind = getKind(*err) 57 } 58 59 r.state.done(nanotime()-r.now, kind) 60 } 61 62 // getKind returns a string that attemps to be representative of the error. 63 func getKind(err error) string { 64 if n, ok := err.(interface{ Name() (string, bool) }); ok { 65 if name, ok := n.Name(); ok { 66 return name 67 } 68 } 69 70 if err != nil { 71 s := err.Error() 72 if i := strings.IndexByte(s, ':'); i > 0 { 73 return s[:i] 74 } else if strings.IndexByte(s, ' ') == -1 { 75 return s 76 } else { 77 return "error" 78 } 79 } 80 81 return "" 82 }