github.com/haraldrudell/parl@v0.4.176/nb-chan-logger.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 import ( 9 "strconv" 10 "time" 11 12 "github.com/haraldrudell/parl/perrors" 13 ) 14 15 const ( 16 // [NBChanLogger] logging thread does not close until channel is closed 17 NBChanExpectClose = true 18 // [NBChanLogger] logging thread exits when channel has been read to empty 19 NBChanWillNotClose = false 20 ) 21 22 // generates labels "1"… separating different channel instances 23 var nbChanLoggerID UniqueIDUint64 24 25 // NBChanLogger is a debug logger for an NBChan instance 26 // - label is a string leading printouts, default a small integer 27 // - NBChan is the channel watched 28 // - printout continues until the channel is empty and the thread has exited 29 // - if expectClose is true, printout will continue until the underlying channel is closed 30 // - log default is parl.Log 31 func NBChanLogger[T any](label string, n *NBChan[T], expectClose bool, log ...PrintfFunc) { 32 if n == nil { 33 panic(perrors.NewPF("nbChan cannot be nil")) 34 } 35 if label == "" { 36 label = strconv.Itoa(int(nbChanLoggerID.ID())) 37 } 38 var log0 PrintfFunc 39 if len(log) > 0 { 40 log0 = log[0] 41 } 42 if log0 == nil { 43 log0 = Log 44 } 45 go doLogging(label, n, expectClose, log0) 46 } 47 48 // doLogging prints NBChan status output every second 49 func doLogging[T any](label string, n *NBChan[T], expectClose bool, log PrintfFunc) { 50 51 // ticker for periodic printing 52 var ticker = time.NewTicker(time.Second) 53 defer ticker.Stop() 54 55 var endCh = n.WaitForCloseCh() 56 for { 57 log(label + "\x20" + NBChanState(n)) 58 59 if n.Count() == 0 && 60 n.ThreadStatus() == NBChanExit && 61 n.sends.Load() == 0 && 62 n.gets.Load() == 0 && 63 (!expectClose || n.DidClose()) { 64 return 65 } 66 67 select { 68 case <-endCh: 69 endCh = nil 70 case <-ticker.C: 71 } 72 } 73 } 74 75 // “length/i/o: 1/0/0 close-now:true-false thread: send sends: 0 gets: 0 always: true-true chClosed: false err: false” 76 func NBChanState[T any](n *NBChan[T]) (s string) { 77 n.inputLock.Lock() 78 var in = len(n.inputQueue) 79 n.inputLock.Unlock() 80 n.outputLock.Lock() 81 var out = len(n.outputQueue) 82 n.outputLock.Unlock() 83 var threadType string 84 if n.isNoThread.Load() { 85 threadType = "-" + NBChanNone.String() 86 } else if n.isOnDemandThread.Load() { 87 threadType = "-" + NBChanOnDemand.String() 88 } 89 var alertValue string 90 if n.tcAlertActive.Load() || n.alertChan2Active.Load() != nil { 91 alertValue = "-alertValue" 92 } 93 var hasData string 94 if n.isDataAvailable.Load() { 95 hasData = "data" 96 } else { 97 hasData = "empty" 98 } 99 100 return Sprintf("length/i/o:%d/%d/%d-%s%s sends/gets:%d/%d thread:%s%s close/now/ch:%t/%t/%t err: %t", 101 102 // “length/i/o: 1/0/0” unsentCount, len input, len output 103 n.Count(), in, out, hasData, alertValue, 104 105 // “send sends: 0 gets: 0” pending Send/SendMany, Get 106 n.sends.Load(), n.gets.Load(), 107 108 // “thread: chSend” ThreadStatus 109 n.ThreadStatus(), threadType, 110 111 // “close-now:true-false” Close-CloseNow 112 n.isCloseInvoked.IsInvoked(), n.isCloseNow.IsInvoked(), n.IsClosed(), 113 114 // “err: false” if NBCHan had panic or close error 115 n.GetError() != nil, 116 ) 117 }