// NewContext creates a new context that is watching a live task. See Start // or MonitorGroup.Task func (t *TaskMonitor) NewContext() *TaskCtx { t.mtx.Lock() t.current += 1 t.total_started += 1 if t.current > t.highwater { t.highwater = t.current } t.mtx.Unlock() return &TaskCtx{start: monotime.Monotonic(), monitor: t} }
// RegisterEnvironment configures the MonitorStore receiver to understand all // sorts of process environment statistics, such as memory statistics, // process uptime, file descriptor use, goroutine use, runtime internals, // Rusage stats, etc. func (store *MonitorStore) RegisterEnvironment() { if store == nil { store = DefaultStore } group := store.GetMonitorsNamed("env") group.Chain("goroutines", MonitorFunc( func(cb func(name string, val float64)) { cb("count", float64(runtime.NumGoroutine())) })) group.Chain("memory", MonitorFunc( func(cb func(name string, val float64)) { var stats runtime.MemStats runtime.ReadMemStats(&stats) MonitorStruct(stats, cb) })) process_crc, err := ProcessCRC() if err != nil { logger.Errorf("failed determining process crc: %s", err) process_crc = 0 } group.Chain("process", MonitorFunc( func(cb func(name string, val float64)) { cb("control", 1) fds, err := FdCount() if err != nil { logger.Errorf("failed getting fd count: %s", err) } else { cb("fds", float64(fds)) } cb("crc", float64(process_crc)) cb("uptime", (monotime.Monotonic() - startTime).Seconds()) })) group.Chain("runtime", MonitorFunc( func(cb func(name string, val float64)) { MonitorStruct(RuntimeInternals(), cb) })) group.Chain("rusage", MonitorFunc( func(cb func(name string, val float64)) { var rusage syscall.Rusage err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage) if err != nil { logger.Errorf("failed getting rusage data: %s", err) return } MonitorStruct(&rusage, cb) })) }
// Finish records a successful task completion. You must pass a pointer to // the named error return value (or nil if there isn't one) and the result // of recover() out of the method that was deferred for this to work right. // Finish will re-panic any recovered panics (provided it wasn't a nil panic) // after bookkeeping. func (c *TaskCtx) Finish(err_ref *error, rec interface{}) { duration_nanoseconds := int64(monotime.Monotonic() - c.start) var error_name string var err error if err_ref != nil { err = *err_ref } if rec != nil { var ok bool err, ok = rec.(error) if !ok || err == nil { err = errors.PanicError.New("%v", rec) } } if err != nil { error_name = errors.GetClass(err).String() max_len := Config.MaxErrorLength if len(error_name) > max_len { error_name = error_name[:max_len] } error_name = SanitizeName(error_name) } // we keep granularity on the order microseconds, which should keep // sum_squared useful duration_microseconds := int64(duration_nanoseconds / microsecondInNanoseconds) c.monitor.mtx.Lock() c.monitor.current -= 1 c.monitor.total_completed += 1 if err != nil { c.monitor.errors[error_name] += 1 if rec != nil { c.monitor.panics += 1 } c.monitor.error_timing.Add(duration_microseconds) } else { c.monitor.success_timing.Add(duration_microseconds) c.monitor.success += 1 } c.monitor.mtx.Unlock() c.monitor.total_timing.Add(duration_microseconds) // doh, we didn't actually want to stop the panic codepath. // we have to repanic. Oh and great, panics can be nil. Welp! if rec != nil { panic(rec) } }
package monitor import ( "fmt" "io" "os" "runtime" "syscall" "github.com/spacemonkeygo/crc" "github.com/spacemonkeygo/monotime" ) var ( startTime = monotime.Monotonic() ) // RegisterEnvironment configures the MonitorStore receiver to understand all // sorts of process environment statistics, such as memory statistics, // process uptime, file descriptor use, goroutine use, runtime internals, // Rusage stats, etc. func (store *MonitorStore) RegisterEnvironment() { if store == nil { store = DefaultStore } group := store.GetMonitorsNamed("env") group.Chain("goroutines", MonitorFunc( func(cb func(name string, val float64)) { cb("count", float64(runtime.NumGoroutine()))
func nowTimestamp() uint32 { return uint32(monotime.Monotonic() / time.Microsecond) }
// Elapsed just returns the amount of time since the timer started func (r *RunningTimer) Elapsed() time.Duration { return monotime.Monotonic() - r.start }
// Start constructs a RunningTimer func (t *Timer) Start() *RunningTimer { return &RunningTimer{ start: monotime.Monotonic(), t: t} }
func (t TaskCtx) ElapsedTime() time.Duration { return monotime.Monotonic() - t.start }