package monitor import ( "leafstalk/log" "leafstalk/otherutils" "reflect" "runtime" "time" ) type Alarm struct { Type int64 `json:"type"` Name string `json:"name"` Args string `json:"args"` CostTime int64 `json:"costTime"` CreatedAt int64 `json:"createdAt"` } var ( reportFunc func(alarm *Alarm) ) func SetReportFunc(f func(alarm *Alarm)) { reportFunc = f } func reportMonitorAlarm(alarm *Alarm) { if reportFunc != nil { reportFunc(alarm) } else { log.Warnf("monitor.reportMonitorAlarm:%v", otherutils.DumpToJSON(alarm)) } } // TimeoutWarn 超时报警 // 这个函数的几个参数说明如下: // funName、args 表示超时发生位置的两个字符串参数 // start 程序开始执行的时间 // timeLimit 函数执行超时阀值,单位是毫秒 func TimeoutWarn(funName string, args any, typ int64, start time.Time, tl ...int64) { timeLimit := DefaultAlarmThreshold if len(tl) > 0 { timeLimit = tl[0] } ct := time.Since(start).Milliseconds() if ct > timeLimit { // 上报报警数据 alarm := new(Alarm) alarm.Type = typ alarm.Name = funName alarm.Args = otherutils.DumpToJSON(args) alarm.CostTime = ct alarm.CreatedAt = start.Unix() reportMonitorAlarm(alarm) } } func GoExecTimeoutWarn(fn any, args any, start time.Time, tl ...int64) { funName := functionName(fn) if funName == "" { return } TimeoutWarn(funName, args, AlarmTypeGoExec, start, tl...) } func GoLoadTimeoutWarn(funName string, playerId int64, start time.Time, tl ...int64) { TimeoutWarn(funName, playerId, AlarmTypeGoLoad, start, tl...) } func GoLoadTimeoutWarn2(funName string, playerId string, start time.Time, tl ...int64) { TimeoutWarn(funName, playerId, AlarmTypeGoLoad, start, tl...) } func MySqlExecTimeoutWarn(funName string, args any, start time.Time, tl ...int64) { TimeoutWarn(funName, args, AlarmTypeMySqlExec, start, tl...) } func RedisDoTimeoutWarn(funName string, args any, start time.Time, tl ...int64) { TimeoutWarn(funName, args, AlarmTypeRedisDo, start, tl...) } func TimeoutWarnCall(f func(), funName string, args any, typ int64, start time.Time, tl ...int64) { defer TimeoutWarn(funName, args, typ, start, tl...) f() } func functionName(fn interface{}) string { fullName := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() // 在完整名称内查找函数名 lastDotIndex := 0 for i := len(fullName) - 1; i >= 0; i-- { if fullName[i] == '.' { lastDotIndex = i break } } funcName := fullName[lastDotIndex+1:] return funcName }