dataMonitor.go 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. package monitor
  2. import (
  3. "scd_check_tools/conf"
  4. Db "scd_check_tools/db"
  5. "scd_check_tools/email"
  6. "scd_check_tools/global"
  7. "scd_check_tools/logger"
  8. "scd_check_tools/models/bo"
  9. "scd_check_tools/sms"
  10. "scd_check_tools/tools"
  11. "fmt"
  12. "log"
  13. "math"
  14. "os"
  15. "os/exec"
  16. "regexp"
  17. "runtime"
  18. "strconv"
  19. "strings"
  20. "sync"
  21. "time"
  22. "github.com/shirou/gopsutil/cpu"
  23. "github.com/shirou/gopsutil/disk"
  24. //"github.com/shirou/gopsutil/load"
  25. "github.com/shirou/gopsutil/mem"
  26. "github.com/astaxie/beego/orm"
  27. )
  28. type DataMonitor struct {
  29. performanceRuntimeMonitorState bool
  30. performanceRuntimeMonitorResult map[string]interface{}
  31. pmResultLock sync.RWMutex
  32. }
  33. var SignDataMonitor = new(DataMonitor)
  34. var DataMonitorMsgChan chan map[string]interface{}
  35. //设备数据处理监控
  36. func StartDataMonitor() {
  37. DataMonitorMsgChan = make(chan map[string]interface{}, 10)
  38. sendMsg := func() {
  39. log.Println("启动短信发送进程")
  40. for {
  41. msgdata, ok := <-DataMonitorMsgChan
  42. if ok {
  43. if msgdata != nil {
  44. smsplatform := conf.GlobalConfig["sms.platform"]
  45. if smsplatform == "" {
  46. log.Println("未配置短信消息发送平台")
  47. } else {
  48. smsSend := sms.GetSmsInstance(smsplatform)
  49. datatype := msgdata["datatype"].(string)
  50. params := msgdata["params"].([]string)
  51. phone := msgdata["phone"].([]string)
  52. if conf.GlobalConfig["loglevel"] == "5" {
  53. log.Println(fmt.Sprintf("%v", msgdata))
  54. }
  55. _, err := smsSend.Send(datatype, params, phone)
  56. if err != nil {
  57. log.Println(err)
  58. }
  59. }
  60. }
  61. }
  62. }
  63. }
  64. go sendMsg()
  65. go dataTimoutMonitorStart()
  66. go dataAlterMonitorStart()
  67. go performanceMonitorStart()
  68. go attachmentMonitorStart()
  69. go StartClearTempScd()
  70. go StateOptimizeTable()
  71. go func() {
  72. for {
  73. select {
  74. case v := <-global.PerformanceRuntimeMonitorChan:
  75. log.Println(fmt.Sprintf("=======================性能监测标识:%d", v))
  76. if v == 1 {
  77. go SignDataMonitor.PerformanceRuntimeMonitorStart()
  78. } else {
  79. go SignDataMonitor.PerformanceRuntimeMonitorStop()
  80. }
  81. }
  82. }
  83. log.Println(fmt.Sprintf("=======================性能监测终止"))
  84. }()
  85. }
  86. //启动每周数据表优化进程
  87. func StateOptimizeTable() {
  88. log.Println("启动每周数据表优化进程")
  89. for {
  90. nowDay, _ := strconv.Atoi(time.Now().Format("02"))
  91. nowHour := time.Now().Format("15")
  92. //每5天优化一次
  93. dbOptimizeMonitorIntervalDay, _ := bo.GetSysParamValue("dbOptimizeMonitorInterval", "5")
  94. dbOptimizeMonitorIntervalDayI, _ := strconv.Atoi(dbOptimizeMonitorIntervalDay)
  95. if nowHour != "02" || (nowDay%dbOptimizeMonitorIntervalDayI != 0) {
  96. time.Sleep(time.Hour * 1)
  97. continue
  98. }
  99. m := new(DataMonitor)
  100. m.OptimizeTable()
  101. time.Sleep(time.Hour * 1)
  102. }
  103. }
  104. //启动定时清理临时SCD数据进程
  105. func StartClearTempScd() {
  106. logger.Logger.Println("启动定时清理临时SCD数据进程")
  107. for {
  108. nowHour := time.Now().Format("15")
  109. //每天凌晨1点清理一次
  110. tempScdMonitorHour, _ := bo.GetSysParamValue("tempScdMonitorHour", "01")
  111. if nowHour != tempScdMonitorHour {
  112. time.Sleep(time.Minute * 50)
  113. continue
  114. }
  115. m := new(DataMonitor)
  116. m.tempScdClear()
  117. time.Sleep(time.Minute * 50)
  118. }
  119. }
  120. //数据采集超时处理进程启动
  121. func dataTimoutMonitorStart() {
  122. log.Println("启动数据超时检查处理进程")
  123. for {
  124. nowHour := time.Now().Format("15")
  125. //每天早上7点检测一次所有设备是否有新数据
  126. dataTimoutMonitorHour, _ := bo.GetSysParamValue("dataTimoutMonitorHour", "07")
  127. if nowHour != dataTimoutMonitorHour {
  128. time.Sleep(time.Minute * 50)
  129. continue
  130. }
  131. //m := new(DataMonitor)
  132. //m.liftStatusDataTimeoutCheck()
  133. //m.doorStatusDataTimeoutCheck()
  134. //m.apStatusDataTimeoutCheck()
  135. //m.cameraStatusDataTimeoutCheck()
  136. //m.parkStatusDataTimeoutCheck()
  137. time.Sleep(time.Minute * 50)
  138. }
  139. }
  140. //设备告警监测进程启动
  141. func dataAlterMonitorStart() {
  142. log.Println("启动数据告警监测处理进程")
  143. }
  144. //常规性能监控.每1分钟监测一次
  145. func performanceMonitorStart() {
  146. log.Println("启动性能监控处理进程")
  147. var err error
  148. osname := string(runtime.GOOS)
  149. cpuHC, _ := strconv.Atoi(tools.IsEmpty(conf.GlobalConfig["alarm_cpu_value"], "90")) //cpu高耗用率
  150. memHC, _ := strconv.Atoi(tools.IsEmpty(conf.GlobalConfig["alarm_mem_value"], "90")) //内存高耗用率
  151. diskHCC, _ := strconv.Atoi(tools.IsEmpty(conf.GlobalConfig["alarm_disk_value"], "90")) //C磁盘高耗用率
  152. diskHCI := diskHCC //程序所在磁盘高耗用率
  153. cpuHC_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  154. memHC_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  155. diskHCC_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  156. diskHCI_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  157. thisIp, _ := tools.LocalIPv4()
  158. if thisIp != "" {
  159. thisIp = "[" + thisIp + "]"
  160. }
  161. appname := conf.GlobalConfig["appname"]
  162. //fmt.Println("======================IP:" + thisIp)
  163. db := orm.NewOrm()
  164. logalarming := false
  165. memalarming := false
  166. cpualarming := false
  167. diskalarming := false
  168. diskcalarming := false //c盘空间
  169. for {
  170. log_alarm_email, _ := bo.GetSysParamValue("log_alarm_email", "")
  171. go func() {
  172. //日志容量监测
  173. sql := "select round(sum(DATA_LENGTH/1024/1024),2) v from information_schema.tables where table_schema=? AND table_name='global_syslog'"
  174. spaceRowset := []orm.Params{}
  175. _, dberr := db.Raw(sql, Db.DbCfg.Db).Values(&spaceRowset)
  176. if dberr != nil {
  177. logger.Logger.Error(dberr)
  178. }
  179. if len(spaceRowset) > 0 {
  180. logspce, _ := strconv.Atoi(tools.IsEmpty(spaceRowset[0]["v"]))
  181. if logspce > 0 {
  182. vmod, _ := bo.GetSysParamValue("log_size_max", "0")
  183. logmax, _ := strconv.Atoi(vmod)
  184. logalarm1, _ := bo.GetSysParamValue("log_size_alarm1", "0")
  185. logalarmv1, _ := strconv.Atoi(logalarm1)
  186. logalarm2, _ := bo.GetSysParamValue("log_size_alarm2", "0")
  187. logalarmv2, _ := strconv.Atoi(logalarm2)
  188. if logmax > 0 {
  189. desc := ""
  190. if logalarmv2*logmax <= logspce {
  191. //告警
  192. desc = fmt.Sprintf("%s日志告警:当前系统日志容量已达 %d MB", appname, logspce)
  193. } else if logalarmv1*logmax <= logspce {
  194. //预警
  195. desc = fmt.Sprintf("%s日志预警:当前系统日志容量已达 %d MB", appname, logspce)
  196. }
  197. if !logalarming && desc != "" {
  198. new(bo.SystemAlarm).Save("1", "log", desc, 0)
  199. logalarming = true
  200. } else if logalarming && desc == "" {
  201. desc = appname + "日志容量预(告)警已解除"
  202. new(bo.SystemAlarm).Save("1", "log", desc, 1)
  203. logalarming = false
  204. }
  205. if desc != "" {
  206. if log_alarm_email != "" {
  207. err := new(email.Send).SendEmail(log_alarm_email, appname+"日志容量预(告)警", desc)
  208. if err != nil {
  209. logger.Logger.Error(err)
  210. }
  211. }
  212. }
  213. }
  214. }
  215. }
  216. }()
  217. sql := "select mobilephone from t_data_user u,global_const_code t where u.role=t.id and t.code='role_sysadmin'"
  218. ps := []orm.Params{}
  219. _, err = db.Raw(sql).Values(&ps)
  220. if err != nil {
  221. log.Println(err)
  222. time.Sleep(5 * time.Minute)
  223. continue
  224. }
  225. devicePhone := []string{}
  226. for _, row := range ps {
  227. p1 := tools.IsEmpty(row["mobilephone"])
  228. if p1 == "" {
  229. continue
  230. }
  231. devicePhone = append(devicePhone, strings.Split(p1, ",")...)
  232. }
  233. if osname == "windows" {
  234. cpuuse_command := "wmic cpu get loadpercentage"
  235. memFree_command := "wmic OS get FreePhysicalMemory"
  236. memTotal_command := "wmic ComputerSystem get TotalPhysicalMemory"
  237. diskuse_command_c := "wmic LogicalDisk where Caption='C:' get FreeSpace,Size /value"
  238. cmd := exec.Command("cmd", "/C", cpuuse_command)
  239. info1, _ := cmd.Output()
  240. info := []byte{}
  241. for _, b := range info1 {
  242. if b == 32 || b == 13 || b == 10 {
  243. continue
  244. }
  245. info = append(info, b)
  246. }
  247. v := string(info)
  248. if v != "" {
  249. v = strings.Trim(strings.ReplaceAll(v, "LoadPercentage", ""), " ")
  250. vint, _ := strconv.Atoi(v)
  251. cpuHC_lst["ishc"] = vint
  252. if vint >= cpuHC {
  253. cpuHC_lst["hcnt"] = cpuHC_lst["hcnt"] + 1
  254. if cpuHC_lst["hcnt"] >= 3 {
  255. if !cpualarming {
  256. msgobj := map[string]interface{}{}
  257. msgobj["datatype"] = sms.TemplateCode_Device_Performance
  258. msgobj["params"] = []string{appname + thisIp, "CPU", fmt.Sprintf("已达%d", vint) + "%"}
  259. msgobj["phone"] = devicePhone
  260. DataMonitorMsgChan <- msgobj
  261. desc := fmt.Sprintf("[%s]系统CPU耗用告警:当前CPU耗用率已达%d%%,请尽快处理!同时系统将限制同时访问的SCD数量!", appname, vint)
  262. new(bo.SystemAlarm).Save("1", "cpu", desc, 0)
  263. if log_alarm_email != "" {
  264. new(email.Send).SendEmail(log_alarm_email, appname+"系统CPU耗用告警", desc)
  265. }
  266. }
  267. cpualarming = true
  268. }
  269. logger.Logger.Println(fmt.Sprintf("!!!警告:当前CPU耗用率已达%d,请尽快处理!同时系统将限制同时访问的SCD数量!", vint))
  270. } else {
  271. cpuHC_lst["hcnt"] = 0
  272. if cpualarming {
  273. desc := fmt.Sprintf("[%s]系统CPU耗用告警解除,当前CPU耗用率%d%%", appname, vint)
  274. new(bo.SystemAlarm).Save("1", "cpu", desc, 1)
  275. if log_alarm_email != "" {
  276. new(email.Send).SendEmail(log_alarm_email, appname+"系统CPU耗用告警解除", desc)
  277. }
  278. }
  279. cpualarming = false
  280. }
  281. global.PerformanceRuntimeMonitorResult.Store("cpu", vint)
  282. }
  283. //总内存.结果的单位为b
  284. cmd = exec.Command("cmd", "/C", memTotal_command)
  285. info1, _ = cmd.Output()
  286. info = []byte{}
  287. for _, b := range info1 {
  288. if b == 32 || b == 13 || b == 10 {
  289. continue
  290. }
  291. info = append(info, b)
  292. }
  293. v = string(info)
  294. totalmem := 0
  295. if v != "" {
  296. v = strings.Trim(strings.ReplaceAll(v, "TotalPhysicalMemory", ""), " ")
  297. totalmem, _ = strconv.Atoi(v)
  298. }
  299. //剩余内存.结果的单位为Kb
  300. cmd = exec.Command("cmd", "/C", memFree_command)
  301. info1, _ = cmd.Output()
  302. info = []byte{}
  303. for _, b := range info1 {
  304. if b == 32 || b == 13 || b == 10 {
  305. continue
  306. }
  307. info = append(info, b)
  308. }
  309. v = string(info)
  310. //logger.Logger.Debug(fmt.Sprintf("====总内存:%d 当前空闲内存:%s", totalmem, v))
  311. if v != "" {
  312. v = strings.Trim(strings.ReplaceAll(v, "FreePhysicalMemory", ""), " ")
  313. vint, _ := strconv.Atoi(v)
  314. if vint > 0 {
  315. memuserate := int((1 - (float32(vint)/1024/1024)/(float32(totalmem)/1024/1024/1024)) * 100)
  316. memHC_lst["ishc"] = memuserate
  317. if memuserate >= memHC {
  318. memHC_lst["hcnt"] = memHC_lst["hcnt"] + 1
  319. if memHC_lst["hcnt"] >= 3 {
  320. if !memalarming {
  321. msgobj := map[string]interface{}{}
  322. msgobj["datatype"] = sms.TemplateCode_Device_Performance
  323. msgobj["params"] = []string{appname + thisIp, "内存", fmt.Sprintf("已达%d", memuserate) + "%"}
  324. msgobj["phone"] = devicePhone
  325. DataMonitorMsgChan <- msgobj
  326. desc := fmt.Sprintf("[%s]系统内存耗用告警:当前内存耗用率已达%d%%,请尽快处理!同时系统将尝试清除访问频率较低的SCD缓存数据!", appname, memuserate)
  327. new(bo.SystemAlarm).Save("1", "mem", desc, 0)
  328. if log_alarm_email != "" {
  329. new(email.Send).SendEmail(log_alarm_email, appname+"系统内存耗用告警", desc)
  330. }
  331. }
  332. memalarming = true
  333. //释放SCD缓存
  334. go new(bo.ScdParse).RemoveScdCache()
  335. }
  336. logger.Logger.Println(fmt.Sprintf("!!!警告:当前内存耗用率已达%d,请尽快处理!同时系统将尝试清除访问频率较低的SCD缓存数据!", memuserate))
  337. } else {
  338. memHC_lst["hcnt"] = 0
  339. if memalarming {
  340. desc := fmt.Sprintf("[%s]系统内存耗用告警解除,当前内存使用率%d%%", appname, memuserate)
  341. new(bo.SystemAlarm).Save("1", "mem", desc, 1)
  342. if log_alarm_email != "" {
  343. new(email.Send).SendEmail(log_alarm_email, appname+"系统内存耗用告警解除", desc)
  344. }
  345. }
  346. memalarming = false
  347. }
  348. global.PerformanceRuntimeMonitorResult.Store("mem", memuserate)
  349. }
  350. }
  351. cmd = exec.Command("cmd", "/C", diskuse_command_c)
  352. info, _ = cmd.Output()
  353. v = string(info)
  354. freeSpace := 0
  355. totalSpace := 0
  356. //logger.Logger.Debug(fmt.Sprintf("====C盘信息:%+v", v))
  357. if v != "" {
  358. for _, tmpv := range strings.Split(strings.Trim(v, " "), "\r\n") {
  359. if strings.TrimSpace(tmpv) == "" {
  360. continue
  361. }
  362. tmpv = strings.ReplaceAll(tmpv, "\r", "")
  363. if strings.HasPrefix(tmpv, "FreeSpace") {
  364. freeSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "FreeSpace=", ""))
  365. if err != nil {
  366. log.Println(err)
  367. }
  368. }
  369. if strings.HasPrefix(tmpv, "Size") {
  370. totalSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "Size=", ""))
  371. if err != nil {
  372. log.Println(err)
  373. }
  374. }
  375. }
  376. //logger.Logger.Debug(fmt.Sprint("====total:%d free:%d ===alarm:%d", totalSpace, freeSpace, diskHCC))
  377. if freeSpace > 0 {
  378. diskHCC_lst["ishc"] = 100 - int(freeSpace*100/totalSpace)
  379. if diskHCC_lst["ishc"] >= diskHCC {
  380. diskHCC_lst["hcnt"] = diskHCC_lst["hcnt"] + 1
  381. if diskHCC_lst["hcnt"] >= 3 {
  382. if !diskcalarming {
  383. msgobj := map[string]interface{}{}
  384. msgobj["datatype"] = sms.TemplateCode_Device_Performance
  385. msgobj["params"] = []string{appname + thisIp, "系统C盘", fmt.Sprintf("已达%d", diskHCC_lst["ishc"]) + "%"}
  386. msgobj["phone"] = devicePhone
  387. DataMonitorMsgChan <- msgobj
  388. desc := fmt.Sprintf("[%s]磁盘C盘剩余空间告警:当前磁盘空间已使用%d%%,请尽快处理!", appname, diskHCC_lst["ishc"])
  389. new(bo.SystemAlarm).Save("1", "disk", desc, 0)
  390. if log_alarm_email != "" {
  391. new(email.Send).SendEmail(log_alarm_email, appname+"系统C盘剩余空间告警", desc)
  392. }
  393. diskcalarming = true
  394. }
  395. }
  396. logger.Logger.Println(fmt.Sprintf("!!!警告:当前系统磁盘占用率已达%d,请尽快处理!", diskHCC_lst["ishc"]))
  397. } else {
  398. diskHCC_lst["hcnt"] = 0
  399. if diskcalarming {
  400. desc := fmt.Sprintf("[%s]磁盘C盘剩余空间告警解除,当前使用空间%d%%", appname, diskHCC_lst["ishc"])
  401. new(bo.SystemAlarm).Save("1", "disk", desc, 1)
  402. if log_alarm_email != "" {
  403. new(email.Send).SendEmail(log_alarm_email, appname+"系统C盘剩余空间告警解除", desc)
  404. }
  405. }
  406. diskcalarming = false
  407. }
  408. global.PerformanceRuntimeMonitorResult.Store("disk_c", diskHCC_lst["ishc"])
  409. }
  410. }
  411. //当前执行路径
  412. exePath := os.Args[0]
  413. //fmt.Println("exePath:", exePath)
  414. exeDisk := strings.Split(exePath, "\\")[0]
  415. diskuse_command_n := "wmic LogicalDisk where Caption='" + exeDisk + "' get FreeSpace,Size /value"
  416. cmd = exec.Command("cmd", "/C", diskuse_command_n)
  417. info, _ = cmd.Output()
  418. v = string(info)
  419. if v != "" {
  420. for _, tmpv := range strings.Split(strings.Trim(v, " "), "\r\n") {
  421. if strings.TrimSpace(tmpv) == "" {
  422. continue
  423. }
  424. tmpv = strings.ReplaceAll(tmpv, "\r", "")
  425. if strings.HasPrefix(tmpv, "FreeSpace") {
  426. freeSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "FreeSpace=", ""))
  427. if err != nil {
  428. log.Println(err)
  429. }
  430. }
  431. if strings.HasPrefix(tmpv, "Size") {
  432. totalSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "Size=", ""))
  433. if err != nil {
  434. log.Println(err)
  435. }
  436. }
  437. }
  438. if freeSpace > 0 {
  439. diskHCI_lst["ishc"] = 100 - int(freeSpace*100/totalSpace)
  440. if diskHCI_lst["ishc"] >= diskHCI {
  441. diskHCI_lst["hcnt"] = diskHCI_lst["hcnt"] + 1
  442. if diskHCI_lst["hcnt"] >= 3 {
  443. if !diskalarming {
  444. msgobj := map[string]interface{}{}
  445. msgobj["datatype"] = sms.TemplateCode_Device_Performance
  446. msgobj["params"] = []string{appname + thisIp, "应用" + exeDisk[0:1] + "盘", fmt.Sprintf("已达%d", diskHCI_lst["ishc"]) + "%"}
  447. msgobj["phone"] = devicePhone
  448. DataMonitorMsgChan <- msgobj
  449. desc := fmt.Sprintf("[%s]磁盘%s盘剩余空间告警:当前磁盘空间已使用%d%%,请尽快处理!", appname, exeDisk[0:1], diskHCI_lst["ishc"])
  450. new(bo.SystemAlarm).Save("1", "disk", desc, 0)
  451. if log_alarm_email != "" {
  452. new(email.Send).SendEmail(log_alarm_email, appname+"系统"+exeDisk[0:1]+"盘剩余空间告警", desc)
  453. }
  454. diskalarming = true
  455. }
  456. logger.Logger.Println(fmt.Sprintf("!!!警告:当前磁盘%s占用率已达%d,请尽快处理!", exeDisk[0:1], diskHCI_lst["ishc"]))
  457. }
  458. } else {
  459. diskHCI_lst["hcnt"] = 0
  460. if diskalarming {
  461. desc := fmt.Sprintf("[%s]磁盘%s盘剩余空间告警已解除,当前磁盘使用%d%%", appname, exeDisk[0:1], diskHCI_lst["ishc"])
  462. new(bo.SystemAlarm).Save("1", "disk", desc, 1)
  463. if log_alarm_email != "" {
  464. new(email.Send).SendEmail(log_alarm_email, appname+"系统"+exeDisk[0:1]+"盘剩余空间告警解除", desc)
  465. }
  466. }
  467. diskalarming = false
  468. }
  469. global.PerformanceRuntimeMonitorResult.Store("disk", diskHCC_lst["ishc"])
  470. }
  471. }
  472. } else {
  473. //linux系统
  474. v, errmem := mem.VirtualMemory()
  475. if errmem != nil {
  476. logger.Logger.Error(errmem)
  477. } else {
  478. //fmt.Printf("内存使用率%d\n", v.UsedPercent)
  479. memuserate := int(v.UsedPercent)
  480. memHC_lst["ishc"] = memuserate
  481. if memuserate >= memHC {
  482. memHC_lst["hcnt"] = memHC_lst["hcnt"] + 1
  483. if memHC_lst["hcnt"] >= 3 {
  484. if !memalarming {
  485. msgobj := map[string]interface{}{}
  486. msgobj["datatype"] = sms.TemplateCode_Device_Performance
  487. msgobj["params"] = []string{appname + thisIp, "内存", fmt.Sprintf("已达%d", memuserate) + "%"}
  488. msgobj["phone"] = devicePhone
  489. DataMonitorMsgChan <- msgobj
  490. desc := fmt.Sprintf("[%s]系统内存耗用告警:当前内存已耗用%d%%,请尽快处理!同时系统将尝试清除访问频率较低的SCD缓存数据!", appname, memuserate)
  491. new(bo.SystemAlarm).Save("1", "mem", desc, 0)
  492. if log_alarm_email != "" {
  493. new(email.Send).SendEmail(log_alarm_email, appname+"系统内存耗用告警", desc)
  494. }
  495. }
  496. memalarming = true
  497. //释放SCD缓存
  498. go new(bo.ScdParse).RemoveScdCache()
  499. }
  500. logger.Logger.Println(fmt.Sprintf("!!!警告:当前内存耗用率已达%d,请尽快处理!同时系统将尝试清除访问频率较低的SCD缓存数据!", memuserate))
  501. } else {
  502. memHC_lst["hcnt"] = 0
  503. if memalarming {
  504. desc := fmt.Sprintf("[%s]系统内存耗用告警已解除,当前内存耗用%d%%", appname, memuserate)
  505. new(bo.SystemAlarm).Save("1", "mem", desc, 1)
  506. if log_alarm_email != "" {
  507. new(email.Send).SendEmail(log_alarm_email, appname+"系统内存耗用告警解除", desc)
  508. }
  509. }
  510. memalarming = false
  511. }
  512. global.PerformanceRuntimeMonitorResult.Store("mem", memuserate)
  513. }
  514. // CPU使用率
  515. //for {
  516. percent, errcpu := cpu.Percent(time.Second, true)
  517. if errcpu != nil {
  518. logger.Logger.Error(errcpu)
  519. } else {
  520. //fmt.Printf("cpu percent:%v", percent)
  521. cpuT := 0.0
  522. for _, v := range percent {
  523. cpuT = cpuT + v
  524. }
  525. cpuavg := int(cpuT / float64(len(percent)))
  526. cpuHC_lst["ishc"] = cpuavg
  527. //fmt.Printf("CPU使用率%d\n", cpuavg)
  528. if cpuavg >= cpuHC {
  529. cpuHC_lst["hcnt"] = cpuHC_lst["hcnt"] + 1
  530. if cpuHC_lst["hcnt"] >= 3 {
  531. if !cpualarming {
  532. msgobj := map[string]interface{}{}
  533. msgobj["datatype"] = sms.TemplateCode_Device_Performance
  534. msgobj["params"] = []string{appname + thisIp, "CPU", fmt.Sprintf("已达%d", cpuavg) + "%"}
  535. msgobj["phone"] = devicePhone
  536. DataMonitorMsgChan <- msgobj
  537. desc := fmt.Sprintf("[%s]系统CPU耗用告警:当前CPU已耗用%d%%,请尽快处理!同时系统将限制同时访问的SCD数量!", appname, cpuavg)
  538. new(bo.SystemAlarm).Save("1", "cpu", desc, 0)
  539. if log_alarm_email != "" {
  540. new(email.Send).SendEmail(log_alarm_email, appname+"系统CPU耗用告警", desc)
  541. }
  542. }
  543. cpualarming = true
  544. }
  545. logger.Logger.Println(fmt.Sprintf("!!!警告:当前CPU耗用率已达%d,请尽快处理!同时系统将限制同时访问的SCD数量!", cpuavg))
  546. } else {
  547. cpuHC_lst["hcnt"] = 0
  548. if cpualarming {
  549. desc := fmt.Sprintf("[%s]系统CPU耗用告警已解除", appname, cpuavg)
  550. new(bo.SystemAlarm).Save("1", "cpu", desc, 1)
  551. if log_alarm_email != "" {
  552. new(email.Send).SendEmail(log_alarm_email, appname+"系统CPU耗用告警解除", desc)
  553. }
  554. }
  555. cpualarming = false
  556. }
  557. global.PerformanceRuntimeMonitorResult.Store("cpu", cpuavg)
  558. }
  559. parts, err2 := disk.Partitions(true)
  560. if err2 != nil {
  561. logger.Logger.Error(err2)
  562. } else {
  563. diskT := 0.0
  564. diskC := 0
  565. for _, part := range parts {
  566. if !strings.HasPrefix(part.Device, "/dev") {
  567. continue
  568. }
  569. //fmt.Printf("part:%v", part.String())
  570. diskInfo, _ := disk.Usage(part.Mountpoint)
  571. diskT = diskT + diskInfo.UsedPercent
  572. diskC = diskC + 1
  573. //fmt.Printf("disk info:used:%v free:%v", diskInfo.UsedPercent, diskInfo.Free)
  574. }
  575. avg := int(diskT / float64(diskC))
  576. diskHCC_lst["ishc"] = avg
  577. //fmt.Printf("磁盘使用率%d\n", avg)
  578. if diskHCC_lst["ishc"] >= diskHCC {
  579. diskHCC_lst["hcnt"] = diskHCC_lst["hcnt"] + 1
  580. if diskHCC_lst["hcnt"] >= 3 {
  581. if !diskalarming {
  582. msgobj := map[string]interface{}{}
  583. msgobj["datatype"] = sms.TemplateCode_Device_Performance
  584. msgobj["params"] = []string{appname + thisIp, "数据磁盘", fmt.Sprintf("已达%d", avg) + "%"}
  585. msgobj["phone"] = devicePhone
  586. DataMonitorMsgChan <- msgobj
  587. desc := fmt.Sprintf("[%s]磁盘空间告警:当前磁盘空间已使用%d%%,请尽快释放多余的空间!", appname, avg)
  588. new(bo.SystemAlarm).Save("1", "disk", desc, 0)
  589. if log_alarm_email != "" {
  590. new(email.Send).SendEmail(log_alarm_email, appname+"系统CPU耗用告警", desc)
  591. }
  592. }
  593. diskalarming = true
  594. }
  595. logger.Logger.Println(fmt.Sprintf("!!!警告:当前磁盘空间占用率已达%d,请尽快释放多余的空间!", avg))
  596. } else {
  597. diskHCC_lst["hcnt"] = 0
  598. if diskalarming {
  599. desc := fmt.Sprintf("[%s]磁盘空间告警已解除", appname, avg)
  600. new(bo.SystemAlarm).Save("1", "disk", desc, 1)
  601. if log_alarm_email != "" {
  602. new(email.Send).SendEmail(log_alarm_email, appname+"磁盘空间告警解除", desc)
  603. }
  604. }
  605. diskalarming = false
  606. }
  607. global.PerformanceRuntimeMonitorResult.Store("disk", avg)
  608. }
  609. }
  610. time.Sleep(1 * time.Minute)
  611. }
  612. }
  613. //启动实时性能监控。每5秒一次并返回结果
  614. func (t *DataMonitor) PerformanceRuntimeMonitorStart() {
  615. if t.performanceRuntimeMonitorState {
  616. return
  617. }
  618. t.pmResultLock = sync.RWMutex{}
  619. t.performanceRuntimeMonitorResult = map[string]interface{}{}
  620. var err error
  621. osname := string(runtime.GOOS)
  622. cpuHC := 80 //cpu高耗用率
  623. memHC := 80 //内存高耗用率
  624. diskHCC := 90 //C磁盘高耗用率
  625. diskHCI := 90 //程序所在磁盘高耗用率
  626. cpuHC_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  627. memHC_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  628. diskHCC_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  629. diskHCI_lst := map[string]int{"ishc": 0, "hcnt": 0, "lcnt": 0}
  630. t.performanceRuntimeMonitorState = true
  631. for {
  632. if !t.performanceRuntimeMonitorState {
  633. break
  634. }
  635. t.pmResultLock.Lock()
  636. if osname == "windows" {
  637. cpuuse_command := "wmic cpu get loadpercentage"
  638. memFree_command := "wmic OS get FreePhysicalMemory"
  639. memTotal_command := "wmic ComputerSystem get TotalPhysicalMemory"
  640. diskuse_command_c := "wmic LogicalDisk where Caption='C:' get FreeSpace,Size /value"
  641. cmd := exec.Command("cmd", "/C", cpuuse_command)
  642. info1, _ := cmd.Output()
  643. info := []byte{}
  644. for _, b := range info1 {
  645. if b == 32 || b == 13 || b == 10 {
  646. continue
  647. }
  648. info = append(info, b)
  649. }
  650. v := string(info)
  651. //log.Println(fmt.Sprintf("====CPU:%s", v))
  652. if v != "" {
  653. v = strings.Trim(strings.ReplaceAll(v, "LoadPercentage", ""), " ")
  654. vint, _ := strconv.Atoi(v)
  655. cpuHC_lst["ishc"] = vint
  656. if vint >= cpuHC {
  657. cpuHC_lst["hcnt"] = cpuHC_lst["hcnt"] + 1
  658. if cpuHC_lst["hcnt"] >= 3 {
  659. t.performanceRuntimeMonitorResult["cpu"] = cpuHC_lst
  660. log.Println(fmt.Sprintf("====CPU:%s", v))
  661. }
  662. } else {
  663. cpuHC_lst["hcnt"] = 0
  664. }
  665. }
  666. //总内存
  667. cmd = exec.Command("cmd", "/C", memTotal_command)
  668. info1, _ = cmd.Output()
  669. info = []byte{}
  670. for _, b := range info1 {
  671. if b == 32 || b == 13 || b == 10 {
  672. continue
  673. }
  674. info = append(info, b)
  675. }
  676. v = string(info)
  677. totalmem := int64(0)
  678. if v != "" {
  679. v = strings.Trim(strings.ReplaceAll(v, "TotalPhysicalMemory", ""), " ")
  680. totalmem, _ = strconv.ParseInt(v, 10, 64)
  681. }
  682. cmd = exec.Command("cmd", "/C", memFree_command)
  683. info1, _ = cmd.Output()
  684. info = []byte{}
  685. for _, b := range info1 {
  686. if b == 32 || b == 13 || b == 10 {
  687. continue
  688. }
  689. info = append(info, b)
  690. }
  691. v = string(info)
  692. //log.Println(fmt.Sprintf("====总内存%d free:%s", totalmem, v))
  693. if v != "" {
  694. v = strings.Trim(strings.ReplaceAll(v, "FreePhysicalMemory", ""), " ")
  695. vint, _ := strconv.ParseInt(v, 10, 64)
  696. if vint > 0 {
  697. var useMem = totalmem - vint*1024
  698. memuserate := (useMem * 100 / totalmem)
  699. //log.Println(fmt.Sprintf("====内存占用率:%d/%d %d", useMem, totalmem, memuserate))
  700. memHC_lst["ishc"] = int(memuserate)
  701. if int(memuserate) >= memHC {
  702. memHC_lst["hcnt"] = memHC_lst["hcnt"] + 1
  703. if memHC_lst["hcnt"] >= 3 {
  704. t.performanceRuntimeMonitorResult["mem"] = memHC_lst
  705. log.Println(fmt.Sprintf("====内存占用率:%d/%d %d", useMem, totalmem, memuserate))
  706. }
  707. } else {
  708. memHC_lst["hcnt"] = 0
  709. }
  710. }
  711. }
  712. cmd = exec.Command("cmd", "/C", diskuse_command_c)
  713. info, _ = cmd.Output()
  714. v = string(info)
  715. freeSpace := 0
  716. totalSpace := 0
  717. if v != "" {
  718. for _, tmpv := range strings.Split(strings.Trim(v, " "), "\r\n") {
  719. if strings.TrimSpace(tmpv) == "" {
  720. continue
  721. }
  722. tmpv = strings.ReplaceAll(tmpv, "\r", "")
  723. if strings.HasPrefix(tmpv, "FreeSpace") {
  724. freeSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "FreeSpace=", ""))
  725. if err != nil {
  726. log.Println(err)
  727. }
  728. }
  729. if strings.HasPrefix(tmpv, "Size") {
  730. totalSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "Size=", ""))
  731. if err != nil {
  732. log.Println(err)
  733. }
  734. }
  735. }
  736. if freeSpace > 0 {
  737. diskHCC_lst["ishc"] = 100 - int(freeSpace*100/totalSpace)
  738. if diskHCC_lst["ishc"] >= diskHCC {
  739. diskHCC_lst["hcnt"] = diskHCC_lst["hcnt"] + 1
  740. if diskHCC_lst["hcnt"] >= 3 {
  741. t.performanceRuntimeMonitorResult["disk"] = diskHCC_lst
  742. }
  743. } else {
  744. diskHCC_lst["hcnt"] = 0
  745. }
  746. }
  747. }
  748. //当前执行路径
  749. exePath := os.Args[0]
  750. //fmt.Println("exePath:", exePath)
  751. exeDisk := strings.Split(exePath, "\\")[0]
  752. diskuse_command_n := "wmic LogicalDisk where Caption='" + exeDisk + "' get FreeSpace,Size /value"
  753. cmd = exec.Command("cmd", "/C", diskuse_command_n)
  754. info, _ = cmd.Output()
  755. v = string(info)
  756. if v != "" {
  757. for _, tmpv := range strings.Split(strings.Trim(v, " "), "\r\n") {
  758. if strings.TrimSpace(tmpv) == "" {
  759. continue
  760. }
  761. tmpv = strings.ReplaceAll(tmpv, "\r", "")
  762. if strings.HasPrefix(tmpv, "FreeSpace") {
  763. freeSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "FreeSpace=", ""))
  764. if err != nil {
  765. log.Println(err)
  766. }
  767. }
  768. if strings.HasPrefix(tmpv, "Size") {
  769. totalSpace, err = strconv.Atoi(strings.ReplaceAll(tmpv, "Size=", ""))
  770. if err != nil {
  771. log.Println(err)
  772. }
  773. }
  774. }
  775. if freeSpace > 0 {
  776. diskHCI_lst["ishc"] = 100 - int(freeSpace*100/totalSpace)
  777. if diskHCI_lst["ishc"] >= diskHCI {
  778. diskHCI_lst["hcnt"] = diskHCI_lst["hcnt"] + 1
  779. if diskHCI_lst["hcnt"] >= 3 {
  780. t.performanceRuntimeMonitorResult["disk_"+exeDisk] = diskHCC_lst
  781. }
  782. } else {
  783. diskHCI_lst["hcnt"] = 0
  784. }
  785. }
  786. }
  787. } else {
  788. //linux系统
  789. v, errmem := mem.VirtualMemory()
  790. if errmem != nil {
  791. log.Println(errmem)
  792. } else {
  793. //log.Printf("内存使用率%d\n", v.UsedPercent)
  794. memuserate := int(v.UsedPercent)
  795. memHC_lst["ishc"] = memuserate
  796. if memuserate >= memHC {
  797. memHC_lst["hcnt"] = memHC_lst["hcnt"] + 1
  798. if memHC_lst["hcnt"] >= 3 {
  799. t.performanceRuntimeMonitorResult["mem"] = memHC_lst
  800. log.Printf("内存使用率%d\n", v.UsedPercent)
  801. }
  802. } else {
  803. memHC_lst["hcnt"] = 0
  804. }
  805. }
  806. percent, errcpu := cpu.Percent(time.Second, true)
  807. if errcpu != nil {
  808. log.Println(errcpu)
  809. } else {
  810. //fmt.Printf("cpu percent:%v", percent)
  811. cpuT := 0.0
  812. for _, v := range percent {
  813. cpuT = cpuT + v
  814. }
  815. cpuavg := int(cpuT / float64(len(percent)))
  816. cpuHC_lst["ishc"] = cpuavg
  817. //fmt.Printf("CPU使用率%d\n", cpuavg)
  818. if cpuavg >= cpuHC {
  819. cpuHC_lst["hcnt"] = cpuHC_lst["hcnt"] + 1
  820. if cpuHC_lst["hcnt"] >= 3 {
  821. t.performanceRuntimeMonitorResult["cpu"] = cpuHC_lst
  822. log.Printf("CPU使用率%d\n", cpuavg)
  823. }
  824. } else {
  825. cpuHC_lst["hcnt"] = 0
  826. }
  827. }
  828. parts, err2 := disk.Partitions(true)
  829. if err2 != nil {
  830. log.Println("get Partitions failed, err:%v", err2)
  831. } else {
  832. diskT := 0.0
  833. diskC := 0
  834. for _, part := range parts {
  835. if !strings.HasPrefix(part.Device, "/dev") {
  836. continue
  837. }
  838. //fmt.Printf("part:%v", part.String())
  839. diskInfo, _ := disk.Usage(part.Mountpoint)
  840. diskT = diskT + diskInfo.UsedPercent
  841. diskC = diskC + 1
  842. //fmt.Printf("disk info:used:%v free:%v", diskInfo.UsedPercent, diskInfo.Free)
  843. }
  844. avg := int(diskT / float64(diskC))
  845. diskHCC_lst["ishc"] = avg
  846. //fmt.Printf("磁盘使用率%d\n", avg)
  847. if diskHCC_lst["ishc"] >= diskHCC {
  848. diskHCC_lst["hcnt"] = diskHCC_lst["hcnt"] + 1
  849. if diskHCC_lst["hcnt"] >= 3 {
  850. t.performanceRuntimeMonitorResult["disk"] = diskHCC_lst
  851. log.Printf("磁盘使用率%d\n", avg)
  852. }
  853. } else {
  854. diskHCC_lst["hcnt"] = 0
  855. }
  856. }
  857. }
  858. t.pmResultLock.Unlock()
  859. //log.Println(fmt.Sprintf("====实时性能监控结果:%v", t.performanceRuntimeMonitorResult))
  860. time.Sleep(5 * time.Second)
  861. }
  862. }
  863. //停止实时性能监控
  864. func (t *DataMonitor) PerformanceRuntimeMonitorStop() {
  865. t.performanceRuntimeMonitorState = false
  866. }
  867. //过期附件监测
  868. func attachmentMonitorStart() {
  869. log.Println("启动过期附件自动清理进程")
  870. for {
  871. nowHour := time.Now().Format("15")
  872. //每天早上0点清理一次
  873. dataTimoutMonitorHour, _ := bo.GetSysParamValue("attachmentClearHour", "00")
  874. if nowHour != dataTimoutMonitorHour {
  875. time.Sleep(time.Minute * 50)
  876. continue
  877. }
  878. m := new(DataMonitor)
  879. m.attachmentAutoClear()
  880. time.Sleep(time.Minute * 50)
  881. }
  882. }
  883. func (t *DataMonitor) OptimizeTable() {
  884. db := orm.NewOrm()
  885. //获取scd属性表
  886. sql := "select table_name , table_comment from information_schema.tables where table_schema = (select database()) and table_name like 't_%' "
  887. rowset := []orm.Params{}
  888. _, err := db.Raw(sql).Values(&rowset)
  889. if err != nil {
  890. log.Println(err)
  891. return
  892. }
  893. for _, row := range rowset {
  894. tb := tools.IsEmpty(row["TABLE_NAME"]) + tools.IsEmpty(row["table_name"])
  895. _, err = db.Raw("optimize table " + tb).Exec()
  896. if err != nil {
  897. log.Println(err)
  898. }
  899. _, err = db.Raw("analyze table " + tb).Exec()
  900. if err != nil {
  901. log.Println(err)
  902. }
  903. }
  904. }
  905. //临时scd数据清理
  906. func (t *DataMonitor) tempScdClear() {
  907. db := orm.NewOrm()
  908. t1 := time.Now().Unix()
  909. clearT := t1 - int64(4*60*60) //4小时之前
  910. clearDate := time.Unix(clearT, 0).Format("2006-01-02 15:04:05")
  911. sql := "select * from t_sys_attachment where check_flag=0 and file_suffix='scd' and scd_id>0 and created_time<?"
  912. rowset := []orm.Params{}
  913. _, err := db.Raw(sql, clearDate).Values(&rowset)
  914. if err != nil {
  915. log.Println(err)
  916. } else {
  917. if len(rowset) == 0 {
  918. return
  919. }
  920. uinfo := map[string]interface{}{}
  921. uinfo["name"] = "临时SCD清理任务"
  922. attach := new(bo.AttachmentMgr)
  923. attach.SetUserInfo(uinfo)
  924. for _, row := range rowset {
  925. id, _ := strconv.Atoi(tools.IsEmpty(row["id"]))
  926. attach.Model = bo.T_sys_attachment{Id: int32(id)}
  927. attach.Delete(false)
  928. }
  929. }
  930. }
  931. //附件自动清理
  932. func (t *DataMonitor) attachmentAutoClear() {
  933. db := orm.NewOrm()
  934. sql := "select * from t_data_attachment where skeepday>0"
  935. list := []orm.Params{}
  936. _, err := db.Raw(sql).Values(&list)
  937. if err != nil {
  938. log.Println(err)
  939. return
  940. }
  941. if len(list) == 0 {
  942. return
  943. }
  944. for _, row := range list {
  945. skeepday := tools.IsEmpty(row["skeepday"])
  946. colname := tools.IsEmpty(row["colname"])
  947. tname := tools.IsEmpty(row["tablename"])
  948. sql1 := "select id," + colname + " from " + tname + " where " + colname + "!='' and CREATED_TIME<DATE_ADD(now(),INTERVAL -" + skeepday + " DAY)"
  949. where := tools.IsEmpty(row["filterwhere"])
  950. if where != "" {
  951. sql1 = sql1 + " and " + where
  952. }
  953. sql1 = sql1 + " limit 0,500 "
  954. for {
  955. tmpresultset := []orm.Params{}
  956. _, err = db.Raw(sql1).Values(&tmpresultset)
  957. if err != nil {
  958. log.Println(err)
  959. break
  960. }
  961. if len(tmpresultset) == 0 {
  962. break
  963. }
  964. ids := []string{}
  965. for _, r := range tmpresultset {
  966. ids = append(ids, tools.IsEmpty(r["id"]))
  967. imgsrc := tools.IsEmpty(r[colname])
  968. if strings.Index(imgsrc, "static/download/") > -1 {
  969. reg, _ := regexp.Compile("http.*?static/download/")
  970. imgsrc = reg.ReplaceAllString(imgsrc, "static/download/")
  971. imgsrc = "./" + imgsrc //物理存储路径
  972. //删除文件
  973. os.Remove(imgsrc)
  974. }
  975. }
  976. _, err = db.Raw("update " + tname + " set " + colname + "='' where id in('" + strings.Join(ids, "','") + "')").Exec()
  977. if err != nil {
  978. log.Println(err)
  979. break
  980. }
  981. }
  982. }
  983. }
  984. func (t *DataMonitor) sendDeviceSms(devicename string, devicelist []string, datatype string, timeout int, devicePhone string) {
  985. if len(devicelist) > 0 {
  986. h := float64(timeout / 3600)
  987. cnt := len(devicelist)
  988. //最多显示5个设备名称
  989. if cnt > 5 {
  990. cnt = 5
  991. }
  992. devicelistNames := strings.Join(devicelist[:cnt], ",")
  993. msgobj := map[string]interface{}{}
  994. msgobj["datatype"] = sms.TemplateCode_Device_Offline
  995. msgobj["params"] = []string{devicename, fmt.Sprintf("%s(共%d台)", devicelistNames, cnt), fmt.Sprintf("%d小时", int(math.Floor(h)))}
  996. msgobj["phone"] = strings.Split(devicePhone, ",")
  997. DataMonitorMsgChan <- msgobj
  998. }
  999. }