monitor.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. package service
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. moniMdl "go-common/app/job/main/aegis/model/monitor"
  7. accApi "go-common/app/service/main/account/api"
  8. upApi "go-common/app/service/main/up/api/v1"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. "go-common/library/xstr"
  12. "math"
  13. "reflect"
  14. "strconv"
  15. "strings"
  16. "time"
  17. )
  18. // monitorArchive 稿件业务监控
  19. // 注意:oa有可能是nil,使用前必须判断!!!
  20. func (s *Service) monitorArchive(act string, oa, na *moniMdl.BinlogArchive) (errs []error) {
  21. var (
  22. c = context.TODO()
  23. logs []string
  24. err error
  25. errs2 []error
  26. nAddit *moniMdl.ArchiveAddit
  27. )
  28. defer func() {
  29. logStr := strings.Join(logs, "\n")
  30. if x := recover(); x != nil {
  31. log.Error("s.monitorArchive() unknown panic(%v)", x)
  32. } else if len(errs) > 0 {
  33. log.Error("s.monitorArchive(\n act: %s \n oa: %+v \n na: %+v) \n logStr:\n %v \n error:%v", act, oa, na, logStr, errs)
  34. } else {
  35. log.Info("s.monitorArchive(\n act: %s \n oa: %+v \n na: %+v) \n logStr:\n %v", act, oa, na, logStr)
  36. }
  37. }()
  38. if (na.Attr>>moniMdl.ArchiveBitPGC)&int64(1) == 1 {
  39. logs = append(logs, "忽略PGC稿件")
  40. return
  41. }
  42. if na == nil {
  43. err = errors.New("new msg nil")
  44. errs = append(errs, err)
  45. logs = append(logs, "databus数据异常,new msg nil")
  46. return
  47. }
  48. na.IsSpecTID = moniMdl.SpecialTypeIDs[na.TypeID]
  49. if nAddit, err = s.moniDao.ArchiveAttr(c, na.ID); err != nil {
  50. logs = append(logs, fmt.Sprintf("warn:稿件Addit获取失败!aid:%d error:%v", na.ID, err))
  51. if err != ecode.NothingFound {
  52. errs = append(errs, err)
  53. return
  54. }
  55. err = nil
  56. } else {
  57. na.Addit = nAddit
  58. }
  59. errs2 = s.monitorHandle(moniMdl.BusArc, *na, na.ID)
  60. errs = append(errs, errs2...)
  61. return
  62. }
  63. // monitorUpDelArc 监控UP主删除稿件。监控指定的UP主。1、在高能联盟的up主特殊用户组;2、粉丝数超过50w
  64. func (s *Service) monitorUpDelArc(id int64, obj interface{}) (satisfy bool, logs []string, err error) {
  65. var (
  66. c = context.TODO()
  67. pReply *accApi.ProfileStatReply
  68. upReply *upApi.HighAllyUpsReply
  69. a *moniMdl.BinlogArchive
  70. )
  71. logs = append(logs, "s.monitorUpDelArc() begin")
  72. if obj == nil {
  73. logs = append(logs, "\t obj是nil")
  74. err = errors.New("obj is nil")
  75. return
  76. }
  77. switch obj.(type) {
  78. case *moniMdl.BinlogArchive:
  79. a = obj.(*moniMdl.BinlogArchive)
  80. case moniMdl.BinlogArchive:
  81. ac := obj.(moniMdl.BinlogArchive)
  82. a = &ac
  83. default:
  84. logs = append(logs, fmt.Sprintf("\t 未知类型:%+v", obj))
  85. err = errors.New("unknown interface type")
  86. return
  87. }
  88. logs = append(logs, fmt.Sprintf("\t archive:%+v", a))
  89. if a == nil {
  90. err = errors.New("archive is nil")
  91. return
  92. }
  93. if a.State != moniMdl.ArchiveStateDel {
  94. logs = append(logs, "\t 非删除,忽略")
  95. return
  96. }
  97. if a.Copyright != moniMdl.ArchiveOriginal {
  98. logs = append(logs, "\t 非自制,忽略")
  99. return
  100. }
  101. if err = s.moniDao.AddToDelArc(c, a); err != nil {
  102. logs = append(logs, fmt.Sprintf("\t 添加删除信息到redis失败。error:%v", err))
  103. err = nil
  104. }
  105. if id == moniMdl.RuleHighUpDelArc {
  106. if upReply, err = s.up.GetHighAllyUps(c, &upApi.HighAllyUpsReq{Mids: []int64{a.MID}}); err != nil {
  107. logs = append(logs, fmt.Sprintf("\t 获取UP主高能信息失败。error:%v", err))
  108. log.Error("\t s.monitorUpDelArc() s.up.GetHighAllyUps() error:%v", err)
  109. }
  110. logs = append(logs, fmt.Sprintf("\t 用户信息:%+v", upReply))
  111. if upReply != nil {
  112. if _, ok := upReply.Lists[a.MID]; ok {
  113. logs = append(logs, "\t UP主属于高能联盟")
  114. satisfy = true
  115. return
  116. }
  117. }
  118. } else if id == moniMdl.RuleFamUpDelArc {
  119. if pReply, err = s.acc.ProfileWithStat3(c, &accApi.MidReq{Mid: a.MID}); err != nil {
  120. logs = append(logs, fmt.Sprintf("\t 获取UP主信息失败。error:%v", err))
  121. log.Error("\t s.monitorUpDelArc() s.acc.ProfileWithStat3() error:%v", err)
  122. }
  123. logs = append(logs, fmt.Sprintf("\t 用户信息:%+v", pReply))
  124. if pReply != nil && pReply.Follower >= 500000 {
  125. logs = append(logs, "\t UP主属于大UP主")
  126. satisfy = true
  127. return
  128. }
  129. }
  130. return
  131. }
  132. // monitorVideo 视频监控
  133. func (s *Service) monitorVideo(act string, ov, nv *moniMdl.BinlogVideo) (errs []error) {
  134. errs = s.monitorHandle(moniMdl.BusVideo, nv, nv.ID)
  135. return
  136. }
  137. // monitorHandle 处理监控数据
  138. func (s *Service) monitorHandle(bid int64, nObj interface{}, oid int64) (errs []error) {
  139. var (
  140. c = context.TODO()
  141. rules []*moniMdl.Rule
  142. logs, logs2 []string
  143. err error
  144. errs2 []error
  145. oKeys, nKeys []string
  146. )
  147. defer func() {
  148. logStr := strings.Join(logs, "\n")
  149. if x := recover(); x != nil {
  150. log.Error("s.monitorHandle() unknown panic(%v)", x)
  151. } else if len(errs) > 0 {
  152. log.Error("s.monitorHandle(\n na: %+v) \n logStr:\n %v \n error:%v", nObj, logStr, errs)
  153. } else {
  154. log.Info("s.monitorHandle(\n na: %+v) \n logStr:\n %v", nObj, logStr)
  155. }
  156. }()
  157. if nObj == nil {
  158. err = errors.New("new msg nil")
  159. errs = append(errs, err)
  160. logs = append(logs, "databus数据异常,new msg nil")
  161. return
  162. }
  163. if rules, err = s.moniDao.RulesByBid(c, bid); err != nil {
  164. logs = append(logs, "获取监控配置失败")
  165. return
  166. }
  167. if len(rules) == 0 {
  168. logs = append(logs, "监控配置不存在")
  169. return
  170. }
  171. for _, rule := range rules {
  172. var allSatisfy = true
  173. //如果是监控UP主大量删稿,则特殊处理
  174. if rule.ID == moniMdl.RuleHighUpDelArc || rule.ID == moniMdl.RuleFamUpDelArc {
  175. if allSatisfy, logs2, err = s.monitorUpDelArc(rule.ID, nObj); err != nil {
  176. errs = append(errs, err)
  177. }
  178. logs = append(logs, logs2...)
  179. } else {
  180. for field, cdt := range rule.RuleConf.MoniCdt {
  181. var (
  182. val int64
  183. satisfy bool
  184. )
  185. if val, err = s.reflectIntVal(nObj, field, 0); err != nil {
  186. errs = append(errs, err)
  187. logs = append(logs, fmt.Sprintf("没有找到字段%s", field))
  188. }
  189. if satisfy, err = s.monitorCompSatisfy(cdt.Comp, val); err != nil {
  190. allSatisfy = false
  191. break
  192. }
  193. if !satisfy {
  194. allSatisfy = false
  195. break
  196. }
  197. }
  198. }
  199. if allSatisfy { //如果满足所有条件,则移入监控
  200. nKeys = append(nKeys, fmt.Sprintf(moniMdl.RedisPrefix, rule.ID))
  201. } else { //如果有条件不满足,则移出监控
  202. oKeys = append(oKeys, fmt.Sprintf(moniMdl.RedisPrefix, rule.ID))
  203. }
  204. }
  205. logs = append(logs, fmt.Sprintf("%d移出keys:%v", oid, oKeys))
  206. logs = append(logs, fmt.Sprintf("%d移入keys:%v", oid, nKeys))
  207. logs2, errs2 = s.monitorSave(oKeys, nKeys, oid)
  208. logs = append(logs, logs2...)
  209. if len(errs2) != 0 {
  210. errs = append(errs, errs2...)
  211. }
  212. return
  213. }
  214. // monitorSave 保存结果
  215. func (s *Service) monitorSave(oKeys, nKeys []string, oid int64) (logs []string, errs []error) {
  216. var (
  217. c = context.TODO()
  218. logs2 []string
  219. err error
  220. )
  221. defer func() {
  222. logStr := strings.Join(logs, "\n")
  223. if x := recover(); x != nil {
  224. log.Error("s.monitorSave() unknown panic(%v)", x)
  225. } else if len(errs) != 0 {
  226. log.Error("s.monitorSave(\n oKeys: %v \n nKeys: %v \n oid: %d) \n logStr:\n %v \n error:%v", oKeys, nKeys, oid, logStr, errs)
  227. } else {
  228. log.Info("s.monitorSave(\n oKeys: %v \n nKeys: %v \n oid: %d) \n logStr:\n %v", oKeys, nKeys, oid, logStr)
  229. }
  230. }()
  231. //从旧key中移出
  232. logs2, err = s.moniDao.RemFromSet(c, oKeys, oid)
  233. logs = append(logs, logs2...)
  234. if err != nil {
  235. errs = append(errs, err)
  236. }
  237. //清除过期的旧key
  238. logs2, err = s.moniDao.ClearExpireSet(c, oKeys)
  239. logs = append(logs, logs2...)
  240. if err != nil {
  241. errs = append(errs, err)
  242. }
  243. //移入到新key
  244. logs2, err = s.moniDao.AddToSet(c, nKeys, oid)
  245. logs = append(logs, logs2...)
  246. if err != nil {
  247. errs = append(errs, err)
  248. }
  249. //清除过期的移入key
  250. logs2, err = s.moniDao.ClearExpireSet(c, nKeys)
  251. logs = append(logs, logs2...)
  252. if err != nil {
  253. errs = append(errs, err)
  254. }
  255. return
  256. }
  257. // monitorNotify 监控报警
  258. func (s *Service) monitorNotify() {
  259. defer func() {
  260. log.Warn("monitorNotify exited.")
  261. }()
  262. var (
  263. c = context.TODO()
  264. err error
  265. rules []*moniMdl.Rule
  266. stats *moniMdl.Stats
  267. min, max int64
  268. )
  269. for {
  270. log.Info("s.monitorNotify() begin")
  271. if rules, err = s.moniDao.ValidRules(c); err != nil {
  272. log.Error("s.monitorNotify() rules:%+v error:%v", rules, err)
  273. time.Sleep(1 * time.Minute)
  274. continue
  275. }
  276. for _, rule := range rules {
  277. if rule.ID == moniMdl.RuleHighUpDelArc || rule.ID == moniMdl.RuleFamUpDelArc {
  278. // 删稿监控特殊处理
  279. s.wg.Add(1)
  280. go s.moniUpDelArcNotify(rule)
  281. continue
  282. }
  283. if min, max, err = s.monitorNotifyTime(rule.RuleConf); err != nil {
  284. log.Error("s.monitorNotify() s.monitorNotifyTime() rule:%+v error:%v", rule, err)
  285. continue
  286. }
  287. if stats, err = s.moniDao.MoniRuleStats(c, rule.ID, min, max); err != nil {
  288. log.Error("s.monitorNotify() s.moniDao.MoniRuleStats(%d,%d,%d) error:%v", rule.ID, min, max, err)
  289. continue
  290. }
  291. notify := s.moniSatisfyNotify(rule.RuleConf, stats)
  292. if notify {
  293. title := fmt.Sprintf("%s监控(aegis)", rule.RuleConf.Name)
  294. body := fmt.Sprintf("当前滞留时间为%s超过阀值,滞留量为%d,整体量为%d \n报警时间:%s", secondsFormat(stats.MaxTime), stats.MoniCount, stats.TotalCount, time.Now().Format("2006-01-02 15:04:05"))
  295. url := ""
  296. switch rule.BID {
  297. case moniMdl.BusVideo:
  298. url = fmt.Sprintf("http://manager.bilibili.co/#!/video/list?monitor_list=%d_%d_%d", rule.Type, rule.BID, rule.ID)
  299. case moniMdl.BusArc:
  300. url = fmt.Sprintf("http://manager.bilibili.co/#!/archive_utils/all?monitor_list=%d_%d_%d", rule.Type, rule.BID, rule.ID)
  301. }
  302. body += fmt.Sprintf("\n跳转链接:<a href=\"%s\">点击跳转</a> %s", url, url)
  303. if err = s.monitorSendNotify(c, rule.RuleConf.Notify.Way, rule.RuleConf.Notify.Member, title, body); err != nil {
  304. log.Error("s.monitorNotify() s.monitorSendNotify(%d,%v,%s,%s) error:%v", rule.RuleConf.Notify.Way, rule.RuleConf.Notify.Member, title, body, err)
  305. }
  306. }
  307. }
  308. time.Sleep(30 * time.Minute)
  309. }
  310. }
  311. // moniSatisfyNotify 检查监控是否满足报警,目前只有数量+时长的条件
  312. func (s *Service) moniSatisfyNotify(conf *moniMdl.RuleConf, stats *moniMdl.Stats) (notify bool) {
  313. notify = true
  314. if _, ok := conf.MoniCdt["time"]; ok {
  315. threshold := conf.NotifyCdt["time"].Value
  316. comp := conf.NotifyCdt["time"].Comp
  317. switch comp {
  318. case moniMdl.CompGT:
  319. if int64(stats.MaxTime) < threshold {
  320. notify = false
  321. }
  322. case moniMdl.CompLT:
  323. if int64(stats.MaxTime) > threshold {
  324. notify = false
  325. }
  326. }
  327. }
  328. if _, ok := conf.NotifyCdt["count"]; ok {
  329. threshold := conf.NotifyCdt["count"].Value
  330. comp := conf.NotifyCdt["count"].Comp
  331. switch comp {
  332. case moniMdl.CompGT:
  333. if int64(stats.MoniCount) < threshold {
  334. notify = false
  335. }
  336. case moniMdl.CompLT:
  337. if int64(stats.MoniCount) > threshold {
  338. notify = false
  339. }
  340. }
  341. }
  342. return
  343. }
  344. // moniUpDelArcNotify 特殊处理UP主删稿的逻辑
  345. func (s *Service) moniUpDelArcNotify(rule *moniMdl.Rule) (err error) {
  346. var (
  347. c = context.TODO()
  348. min, max int64
  349. oidMap map[int64]int
  350. oids, mids []int64
  351. infos map[int64]*moniMdl.DelArcInfo
  352. delMap map[int64][]*moniMdl.DelArcInfo
  353. accStats map[int64]*accApi.ProfileStatReply
  354. threshold int
  355. )
  356. defer func() {
  357. s.wg.Done()
  358. }()
  359. if _, ok := rule.RuleConf.NotifyCdt["count"]; !ok {
  360. err = errors.New("notify count config error")
  361. log.Error("s.moniUpDelArcNotify(%+v) 没有count监控配置", rule)
  362. return
  363. }
  364. threshold = int(rule.RuleConf.NotifyCdt["count"].Value)
  365. delMap = make(map[int64][]*moniMdl.DelArcInfo)
  366. min, max, err = s.monitorNotifyTime(rule.RuleConf)
  367. if err != nil {
  368. log.Error("s.monitorNotifyTime() rule:%+v error:%v", rule, err)
  369. return
  370. }
  371. if oidMap, err = s.moniDao.MoniRuleOids(c, rule.ID, min, max); err != nil {
  372. log.Error("s.moniDao.MoniRuleOids() rule:%+v error:%v", rule, err)
  373. return
  374. }
  375. for oid := range oidMap {
  376. oids = append(oids, oid)
  377. }
  378. if infos, err = s.moniDao.ArcDelInfos(c, oids); err != nil {
  379. log.Error("s.moniUpDelArcNotify() s.moniDao.ArcDelInfos(%v) error(%v)", oids, err)
  380. return
  381. }
  382. for _, info := range infos {
  383. delMap[info.MID] = append(delMap[info.MID], info)
  384. mids = append(mids, info.MID)
  385. }
  386. if accStats, err = s.multiAccounts(c, mids); err != nil {
  387. log.Error("s.moniUpDelArcNotify() s.multiAccounts(%v) error(%v)", mids, err)
  388. accStats = make(map[int64]*accApi.ProfileStatReply)
  389. }
  390. for mid, ins := range delMap {
  391. if _, ok := accStats[mid]; !ok {
  392. log.Error("s.monitorNotify() account ")
  393. accStats[mid] = &accApi.ProfileStatReply{
  394. Profile: &accApi.Profile{
  395. Name: "nil",
  396. Mid: mid,
  397. },
  398. }
  399. }
  400. if len(ins) >= threshold {
  401. var (
  402. title, content string
  403. )
  404. for _, v := range ins {
  405. if title == "" {
  406. title = fmt.Sprintf("【异常删稿报警】“%s” 24内已删除%d个自制稿件 ", accStats[mid].Profile.Name, len(ins))
  407. }
  408. if content == "" {
  409. content = fmt.Sprintf("监控规则:%d——%s——%s<br />报警时间:%s<br /><br />", rule.ID, rule.Name, rule.RuleConf.Name, time.Now().Format("2006-01-02 15:04:05"))
  410. content += fmt.Sprintf("<b>UP主昵称:%s;mid: %d;当前粉丝数:%d; 24内已删除:%d;</b><br /><br />", accStats[mid].Profile.Name, accStats[mid].Profile.Mid, accStats[mid].Follower, len(ins))
  411. content += "<table border=\"1\" style=\"border-collapse: collapse;\"><tr><th>标题</th><th>av号</th><th>删除时间</th></tr>"
  412. }
  413. content += fmt.Sprintf("<tr><td style=\"padding: 5px 10px;\"> %s </td><td style=\"padding: 5px 10px;\"> %d </td><td style=\"padding: 5px 10px;\"> %s </td></tr>", v.Title, v.AID, v.Time)
  414. }
  415. content += "</table>"
  416. if err = s.monitorSendNotify(c, rule.RuleConf.Notify.Way, rule.RuleConf.Notify.Member, title, content); err != nil {
  417. log.Error("s.moniUpDelArcNotify(%d) s.monitorSendNotify(%d,%v,%s,%s) error:%v", rule.ID, rule.RuleConf.Notify.Way, rule.RuleConf.Notify.Member, title, content, err)
  418. }
  419. }
  420. }
  421. return
  422. }
  423. // monitorNotifyTime 计算监控报警的score区间
  424. func (s *Service) monitorNotifyTime(conf *moniMdl.RuleConf) (tFrom, tTo int64, err error) {
  425. now := time.Now().Unix()
  426. if _, ok := conf.NotifyCdt["time"]; !ok {
  427. err = errors.New("配置的 NotifyCdt 中不存在 time")
  428. return
  429. }
  430. timeCdt := conf.NotifyCdt["time"].Value
  431. compCdt := conf.NotifyCdt["time"].Comp
  432. switch compCdt {
  433. case moniMdl.CompGT:
  434. tFrom = 0
  435. tTo = now - timeCdt
  436. case moniMdl.CompLT:
  437. tFrom = now - timeCdt
  438. tTo = now
  439. default:
  440. err = errors.New("配置的 NotifyCdt 中 comparison 不合法: " + compCdt)
  441. return
  442. }
  443. return
  444. }
  445. // reflectIntVal 反射Int值。支持多级查询,比如Addit.MissionID。
  446. func (s *Service) reflectIntVal(obj interface{}, field string, dep int) (val int64, err error) {
  447. if dep > 10 {
  448. err = fmt.Errorf("too deep:%d", dep)
  449. return
  450. }
  451. if obj == nil {
  452. err = errors.New("s.reflectIntVal() obj is invalid memory address or nil pointer dereference")
  453. return
  454. }
  455. if reflect.TypeOf(obj).Kind() == reflect.Ptr {
  456. dep += 1
  457. return s.reflectIntVal(reflect.ValueOf(obj).Elem().Interface(), field, dep)
  458. }
  459. if strings.Contains(field, ".") {
  460. fs := strings.Split(field, ".")
  461. for i, v := range fs {
  462. f := strings.Join(fs[i+1:], ".")
  463. fv := reflect.ValueOf(obj).FieldByName(v)
  464. if !fv.IsValid() {
  465. err = fmt.Errorf("s.reflectIntVal() field not found. field:%s obj: %+v", field, obj)
  466. return
  467. }
  468. if fv.IsNil() {
  469. err = fmt.Errorf("s.reflectIntVal() field is nil. field:%s obj: %+v", field, obj)
  470. return
  471. }
  472. dep += 1
  473. return s.reflectIntVal(fv.Elem().Interface(), f, dep)
  474. }
  475. } else {
  476. fv := reflect.ValueOf(obj).FieldByName(field)
  477. if !fv.IsValid() {
  478. err = fmt.Errorf("s.reflectIntVal() field not found. field:%s obj: %+v", field, obj)
  479. return
  480. }
  481. val = fv.Int()
  482. }
  483. return
  484. }
  485. // monitorCompSatisfy 验证值是否满足监控表达式
  486. func (s *Service) monitorCompSatisfy(com string, val int64) (is bool, err error) {
  487. var (
  488. v int64
  489. vals []int64
  490. )
  491. //暂时支持!=、>、<、=、in
  492. if strings.Contains(com, "!=") {
  493. //"!=10"
  494. if v, err = strconv.ParseInt(strings.Replace(com, "!=", "", -1), 10, 64); err != nil {
  495. return
  496. }
  497. is = v != val
  498. } else if strings.Contains(com, ">=") {
  499. //">=10"
  500. if v, err = strconv.ParseInt(strings.Replace(com, ">=", "", -1), 10, 64); err != nil {
  501. return
  502. }
  503. is = val >= v
  504. } else if strings.Contains(com, "<=") {
  505. //"<=10"
  506. if v, err = strconv.ParseInt(strings.Replace(com, "<=", "", -1), 10, 64); err != nil {
  507. return
  508. }
  509. is = val <= v
  510. } else if strings.Contains(com, "=") {
  511. //"=10"
  512. if v, err = strconv.ParseInt(strings.Replace(com, "=", "", -1), 10, 64); err != nil {
  513. return
  514. }
  515. is = v == val
  516. } else if strings.Contains(com, "!in") {
  517. //"in(1,2,3)"
  518. com = strings.Replace(com, "!in(", "", -1)
  519. com = strings.Replace(com, ")", "", -1)
  520. if vals, err = xstr.SplitInts(com); err != nil {
  521. return
  522. }
  523. is = true
  524. for _, v := range vals {
  525. if val == v {
  526. is = false
  527. break
  528. }
  529. }
  530. } else if strings.Contains(com, "in") {
  531. //"in(1,2,3)"
  532. com = strings.Replace(com, "in(", "", -1)
  533. com = strings.Replace(com, ")", "", -1)
  534. if vals, err = xstr.SplitInts(com); err != nil {
  535. return
  536. }
  537. for _, v := range vals {
  538. if val == v {
  539. is = true
  540. break
  541. }
  542. }
  543. } else if strings.Contains(com, ">") {
  544. //">10"
  545. if v, err = strconv.ParseInt(strings.Replace(com, ">", "", -1), 10, 64); err != nil {
  546. return
  547. }
  548. is = val > v
  549. } else if strings.Contains(com, "<") {
  550. //"<10"
  551. if v, err = strconv.ParseInt(strings.Replace(com, "<", "", -1), 10, 64); err != nil {
  552. return
  553. }
  554. is = val < v
  555. } else {
  556. err = errors.New("unknown comparison")
  557. }
  558. return
  559. }
  560. // monitorSendNotify 发送监控通知
  561. func (s *Service) monitorSendNotify(c context.Context, way int8, members []string, title, content string) (err error) {
  562. switch way {
  563. case moniMdl.NotifyTypeEmail:
  564. log.Info("s.monitorSendNotify() begin. way:%d members:%v title:%s content:%s", way, members, title, content)
  565. if err = s.email.MonitorEmailAsync(c, members, title, content); err != nil {
  566. log.Error("s.email.SendMonitorNotify(%v,%s,%s) error:%v", members, title, content, err)
  567. return
  568. }
  569. default:
  570. err = errors.New("unknown notify way")
  571. log.Error("s.monitorSendNotify(%d,%v,%s,%s) unknown notify way", way, members, title, content)
  572. return
  573. }
  574. return
  575. }
  576. // multiAccounts 批量获取用户数据
  577. func (s *Service) multiAccounts(c context.Context, mids []int64) (res map[int64]*accApi.ProfileStatReply, err error) {
  578. var (
  579. mark map[int64]bool
  580. )
  581. res = make(map[int64]*accApi.ProfileStatReply)
  582. mark = make(map[int64]bool)
  583. if len(mids) == 0 {
  584. return
  585. }
  586. for _, v := range mids {
  587. if mark[v] {
  588. continue
  589. }
  590. mark[v] = true
  591. var r *accApi.ProfileStatReply
  592. if r, err = s.acc.ProfileWithStat3(c, &accApi.MidReq{Mid: v}); err != nil {
  593. log.Error("s.multiAccounts() s.acc.ProfileWithStat3(%d) error(%v)", v, err)
  594. continue
  595. }
  596. res[v] = r
  597. }
  598. return
  599. }
  600. // monitorEmailProc 发送监控邮件任务
  601. func (s *Service) monitorEmailProc() {
  602. defer s.wg.Done()
  603. for {
  604. s.email.MonitorEmailProc()
  605. time.Sleep(200 * time.Millisecond)
  606. }
  607. }
  608. // secondsFormat 将秒转成 时:分:秒
  609. func secondsFormat(sec int) (str string) {
  610. if sec < 0 {
  611. return "--:--:--"
  612. }
  613. if sec == 0 {
  614. return "00:00:00"
  615. }
  616. h := math.Floor(float64(sec) / 3600)
  617. m := math.Floor((float64(sec) - 3600*h) / 60)
  618. se := sec % 60
  619. return fmt.Sprintf("%02d:%02d:%02d", int64(h), int64(m), se)
  620. }