package robot import ( "fmt" "go_dreamfactory/lego/core" "go_dreamfactory/lego/core/cbase" "go_dreamfactory/lego/sys/log" "go_dreamfactory/utils" "os" "sort" "sync" "time" ) /* 统计组件 */ type statisticalComp struct { cbase.ModuleCompBase module *RobotModule succclientNum int32 //链接成功客户端数 failclientNum int32 //链接失败客户端数 curonlineNum int32 //当前在线人数 maxonlineNum int32 //最大在线人数 robotdata map[string][]*RobotStatistics //机器人统计数据 receiveMsg map[string]int32 //接收消息数统计 receiveMsgSize map[string]int64 //接收消息数统计 lock sync.RWMutex start time.Time //开始时间 end time.Time //结束时间 } //组件初始化接口 func (this *statisticalComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.ModuleCompBase.Init(service, module, comp, options) this.module = module.(*RobotModule) this.robotdata = make(map[string][]*RobotStatistics) this.receiveMsg = make(map[string]int32) this.receiveMsgSize = make(map[string]int64) return } func (this *statisticalComp) Start() (err error) { err = this.ModuleCompBase.Start() this.start = time.Now() go this.run() return } //添加成功客户端数 func (this *statisticalComp) AddSuccClient(robot *Robot) { this.lock.Lock() this.curonlineNum++ if this.curonlineNum > this.maxonlineNum { this.maxonlineNum = this.curonlineNum } this.lock.Unlock() } //添加失败客户端数 func (this *statisticalComp) AddFailClient(robot *Robot, err error) { this.failclientNum++ } //机器人测试结束 func (this *statisticalComp) RobotFinishedTest(robot *Robot) { this.lock.Lock() this.robotdata[robot.Account()] = robot.statistics for k, v := range robot.receiveNum { this.receiveMsg[k] += v } for k, v := range robot.receiveSize { this.receiveMsgSize[k] += v } this.curonlineNum-- this.succclientNum++ this.end = time.Now() this.lock.Unlock() } //输出报表 func (this *statisticalComp) OutReport() { var ( messagestime map[string][]int64 = make(map[string][]int64) requestsize map[string]int64 = make(map[string]int64) receive map[string]int32 = make(map[string]int32) receiveSize map[string]int64 = make(map[string]int64) totalmessage int32 totalrequestSize int64 totalreceive int32 totalreceiveSize int64 ok bool ) this.lock.RLock() for _, datas := range this.robotdata { for _, v := range datas { totalmessage++ if _, ok = messagestime[v.message]; !ok { messagestime[v.message] = make([]int64, 0) } messagestime[v.message] = append(messagestime[v.message], v.time) requestsize[v.message] += v.reqsize totalrequestSize += v.reqsize } } for k, v := range this.receiveMsg { receive[k] = v totalreceive += v } for k, v := range this.receiveMsgSize { receiveSize[k] = v totalreceiveSize += v } this.lock.RUnlock() file, err := os.OpenFile(this.module.options.OutFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { fmt.Println(err) return } defer file.Close() file.WriteString(fmt.Sprintf("机器人总数: %d\n", this.module.options.RobotTotalNum)) file.WriteString(fmt.Sprintf("成功数量: %d\n", this.succclientNum)) file.WriteString(fmt.Sprintf("失败数量: %d\n", this.failclientNum)) file.WriteString(fmt.Sprintf("最大同时在线人数: %d\n", this.maxonlineNum)) file.WriteString(fmt.Sprintf("消息总请求数: %d\n", totalmessage)) file.WriteString(fmt.Sprintf("消息总请求大小: %s\n", utils.FormatByesSize(totalrequestSize))) file.WriteString(fmt.Sprintf("消息总接收数: %d\n", totalreceive)) file.WriteString(fmt.Sprintf("消息总接收大小: %s\n", utils.FormatByesSize(totalreceiveSize))) file.WriteString(fmt.Sprintf("压测执行时长: %.2f秒\n", this.end.Sub(this.start).Seconds())) file.WriteString(fmt.Sprintf("QPS: %.2f\n", float64(totalmessage)/this.end.Sub(this.start).Seconds())) file.WriteString("---消息压测详情----------------------------------------------------------------------------------------------------\n") for message, data := range messagestime { sort.Slice(data, func(i, j int) bool { return data[i] < data[j] }) reqsize := requestsize[message] respsize := receiveSize[message] max := data[len(data)-1] min := data[0] sum := int64(0) for _, num := range data { sum += num } avg := float64(sum) / float64(len(data)) var median float64 if len(data)%2 == 0 { median = float64(data[len(data)/2-1]+data[len(data)/2]) / 2.0 } else { median = float64(data[len(data)/2]) } file.WriteString(fmt.Sprintf("消息名:%-30s 请求次数:%-5d 请求数据:%-10s --%-2.2f%% 接收数据:%-10s --%-2.2f%% 耗时最小:%-5dms 耗时最大:%-5dms 平均耗时:%-5.2fms 中位耗时:%-5.2fms \n", message, len(data), utils.FormatByesSize(reqsize), 100*(float32(reqsize)/float32(totalrequestSize)), utils.FormatByesSize(respsize), 100*(float32(respsize)/float32(totalreceiveSize)), min, max, avg, median)) } for k, v := range receive { if _, ok = messagestime[k]; !ok { file.WriteString(fmt.Sprintf("消息名:%-30s 推送次数:%-5d 数据大小:%-5s --%-2.2f%% \n", k, v, utils.FormatByesSize(receiveSize[k]), 100*(float32(receiveSize[k])/float32(totalreceiveSize)))) } } } func (this *statisticalComp) run() { timer := time.NewTicker(time.Second * 10) locp: for { select { case <-timer.C: this.OutReport() if this.failclientNum+this.succclientNum >= this.module.options.RobotTotalNum { break locp } } } timer.Stop() log.Debug("[机器人 WTask]") }