714 lines
26 KiB
Go
714 lines
26 KiB
Go
|
package service
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"encoding/json"
|
|||
|
"math"
|
|||
|
"sort"
|
|||
|
"strconv"
|
|||
|
"strings"
|
|||
|
"time"
|
|||
|
|
|||
|
"go-common/app/admin/ep/melloi/conf"
|
|||
|
"go-common/app/admin/ep/melloi/model"
|
|||
|
"go-common/library/log"
|
|||
|
)
|
|||
|
|
|||
|
// QueryReportSummarys query report summary
|
|||
|
func (s *Service) QueryReportSummarys(c context.Context, sessionID string, qrsr *model.QueryReportSuRequest) (qrs *model.QueryReportSuResponse, err error) {
|
|||
|
// 获取服务树节点
|
|||
|
var treeNodes, treeNodesd []string
|
|||
|
if treeNodesd, err = s.QueryUserRoleNode(c, sessionID); err != nil {
|
|||
|
log.Error("QueryUserRoleNode (%v): ", err)
|
|||
|
return
|
|||
|
}
|
|||
|
treeNodes = append(treeNodesd, "")
|
|||
|
if ExistsInSlice(qrsr.Executor, conf.Conf.Melloi.Executor) {
|
|||
|
if qrs, err = s.dao.QueryReportSummarysWhiteName(&qrsr.ReportSummary, qrsr.SearchAll, qrsr.PageNum, qrsr.PageSize); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
} else {
|
|||
|
if qrs, err = s.dao.QueryReportSummarys(&qrsr.ReportSummary, qrsr.SearchAll, qrsr.PageNum, qrsr.PageSize, treeNodes); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 获取label
|
|||
|
for _, report := range qrs.ReportSummarys {
|
|||
|
lr := model.LabelRelation{Type: model.ReportType, TargetID: int64(report.ID)}
|
|||
|
if report.Labels, err = s.dao.QueryLabelRelation(&lr); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// QueryReportByID Query Report By ID
|
|||
|
func (s *Service) QueryReportByID(id int) (summary *model.ReportSummary, err error) {
|
|||
|
return s.dao.QueryReportSuryByID(id)
|
|||
|
}
|
|||
|
|
|||
|
// CountQueryReportSummarys count query report summarys
|
|||
|
func (s *Service) CountQueryReportSummarys(reportSummary *model.ReportSummary) (int, error) {
|
|||
|
return s.dao.CountQueryReportSummarys(reportSummary)
|
|||
|
}
|
|||
|
|
|||
|
// UpdateReportSummary update report summary
|
|||
|
func (s *Service) UpdateReportSummary(reportSummary *model.ReportSummary) (status string, err error) {
|
|||
|
if err = s.dao.UpdateReportSummary(reportSummary); err != nil {
|
|||
|
status = "update fail"
|
|||
|
return
|
|||
|
}
|
|||
|
status = "success"
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// UpdateReportStatus update report summary status
|
|||
|
func (s *Service) UpdateReportStatus(status int) error {
|
|||
|
return s.dao.UpdateReportStatus(status)
|
|||
|
}
|
|||
|
|
|||
|
// AddReSummaryByPtest Add ReSummary By Ptest
|
|||
|
func (s *Service) AddReSummaryByPtest(ptestParam model.DoPtestParam, jobName, executeID string, testNameNicks []string, snapID, Debug int) (reportSuID int, err error) {
|
|||
|
reportSummary := model.ReportSummary{
|
|||
|
JobName: jobName,
|
|||
|
TestStatus: 2,
|
|||
|
UserName: ptestParam.UserName,
|
|||
|
ResJtl: ptestParam.ResJtl,
|
|||
|
JmeterLog: ptestParam.JmeterLog,
|
|||
|
Department: ptestParam.Department,
|
|||
|
Project: ptestParam.Project,
|
|||
|
APP: ptestParam.APP,
|
|||
|
ScriptID: ptestParam.ScriptID,
|
|||
|
DockerSum: 1,
|
|||
|
Active: 1,
|
|||
|
Debug: Debug,
|
|||
|
ScriptSnapID: snapID,
|
|||
|
ExecuteID: executeID,
|
|||
|
SceneID: ptestParam.SceneID,
|
|||
|
Type: ptestParam.Type,
|
|||
|
LoadTime: ptestParam.LoadTime,
|
|||
|
}
|
|||
|
//Upload==true,这里表示从前端上传的脚本,testNames 和 testNameNicks 长度可能大于1,需要遍历,写入 reportSummary
|
|||
|
if ptestParam.Upload {
|
|||
|
reportSummary.TestNameNick = SliceToString(testNameNicks, ",")
|
|||
|
reportSummary.TestName = ptestParam.ProjectName
|
|||
|
reportSummary.Type = model.PROTOCOL_SCENE
|
|||
|
}
|
|||
|
|
|||
|
// 从页面上直接输入参数生成的单场景脚本,testNames 和 testNameNicks 长度都是 1
|
|||
|
// 生成的场景脚本,ptestParam.TestNameNick 不为空
|
|||
|
if !ptestParam.Upload {
|
|||
|
for _, testName := range ptestParam.TestNames {
|
|||
|
reportSummary.TestNameNick = QueryTestNameNick(testName, testNameNicks)
|
|||
|
reportSummary.TestName = testName
|
|||
|
}
|
|||
|
//场景脚本的 reportSummary 逻辑
|
|||
|
if ptestParam.Type == model.PROTOCOL_SCENE && ptestParam.TestNameNick != "" {
|
|||
|
reportSummary.TestNameNick = ptestParam.TestNameNick
|
|||
|
reportSummary.TestName = ptestParam.SceneName
|
|||
|
}
|
|||
|
}
|
|||
|
if reportSuID, err = s.dao.AddReportSummary(&reportSummary); err != nil {
|
|||
|
log.Error("s.dao.AddReportSummary err :(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// AddReportSummary add report summary
|
|||
|
func (s *Service) AddReportSummary(reportSummary *model.ReportSummary) (status string, reportSuID int, err error) {
|
|||
|
var total int
|
|||
|
if total, err = s.dao.CountQueryReportSummarys(reportSummary); err != nil {
|
|||
|
log.Error("CountQueryReportSummarys error:(%v)", err)
|
|||
|
status = "fail"
|
|||
|
return
|
|||
|
}
|
|||
|
if (total == 1) || (reportSummary.TestName == "") {
|
|||
|
status = "数据已存在或者无接口名"
|
|||
|
} else {
|
|||
|
if reportSuID, err = s.dao.AddReportSummary(reportSummary); err != nil {
|
|||
|
status = "fail"
|
|||
|
return
|
|||
|
}
|
|||
|
status = "success"
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// QueryReGraph query reGraph
|
|||
|
func (s *Service) QueryReGraph(testNameNicks []string) (reportGraphssd [][]model.ReportGraph, err error) {
|
|||
|
var (
|
|||
|
TestNames []string
|
|||
|
reportGraphss []model.ReportGraph
|
|||
|
reportGraphs []model.ReportGraph
|
|||
|
)
|
|||
|
if reportGraphs, err = s.dao.QueryReportGraph(testNameNicks); err != nil {
|
|||
|
log.Error("dao.QueryReportGraph error:(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
if len(reportGraphs) > 0 {
|
|||
|
for _, reportGraph := range reportGraphs {
|
|||
|
TestNames = append(TestNames, reportGraph.TestName)
|
|||
|
}
|
|||
|
TestNamesd := RemoveRepByMap(TestNames)
|
|||
|
for _, testName := range TestNamesd {
|
|||
|
for _, reportGraph := range reportGraphs {
|
|||
|
if reportGraph.TestName == testName {
|
|||
|
reportGraphss = append(reportGraphss, reportGraph)
|
|||
|
}
|
|||
|
}
|
|||
|
reportGraphssd = append(reportGraphssd, reportGraphss)
|
|||
|
reportGraphss = []model.ReportGraph{}
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// QueryClientMoni query client moni
|
|||
|
func (s *Service) QueryClientMoni(cli *model.ClientMoni) (clientMonisd [][]*model.ClientMoni, err error) {
|
|||
|
var (
|
|||
|
jobNames []string
|
|||
|
clientMoniss []*model.ClientMoni
|
|||
|
clientMonis []*model.ClientMoni
|
|||
|
)
|
|||
|
if clientMonis, err = s.dao.QueryClientMoni(cli); err != nil {
|
|||
|
log.Error("dao.QueryClientMoni error:(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
if len(clientMonis) > 0 {
|
|||
|
for _, clientMoni := range clientMonis {
|
|||
|
jobNames = append(jobNames, clientMoni.JobName)
|
|||
|
}
|
|||
|
jobNamesd := RemoveRepByMap(jobNames)
|
|||
|
for _, jobNamed := range jobNamesd {
|
|||
|
for _, clientMoni := range clientMonis {
|
|||
|
if clientMoni.JobName == jobNamed {
|
|||
|
clientMoniss = append(clientMoniss, clientMoni)
|
|||
|
}
|
|||
|
}
|
|||
|
clientMonisd = append(clientMonisd, clientMoniss)
|
|||
|
clientMoniss = []*model.ClientMoni{}
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//QueryReGraphAvg query reGraph
|
|||
|
func (s *Service) QueryReGraphAvg(testNameNicks []string) (reportGraphAvgs []model.ReportGraph, err error) {
|
|||
|
var reportGraphssd [][]model.ReportGraph
|
|||
|
if reportGraphssd, err = s.QueryReGraph(testNameNicks); err != nil {
|
|||
|
log.Error("QueryReGraph error :(%s)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
for _, reportGraphsd := range reportGraphssd {
|
|||
|
reportGraph := ReportGraphAvg(reportGraphsd)
|
|||
|
reportGraphAvgs = append(reportGraphAvgs, reportGraph)
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//ReportGraphAvg report graph avg
|
|||
|
func ReportGraphAvg(reportGraphs []model.ReportGraph) (reportGraph model.ReportGraph) {
|
|||
|
var sumTime, sumQPS, sumNetIo, min, max, sumCount, sumError, sumCodeEll, sumCodeWll, sumCodeWly, sumCodeWle, sumCodeWls,
|
|||
|
sumCodeSll, sumCodeSly, sumCodeSls, sumCodeKong, sumCodeNonHTTP, sumCodeOthers, fiftyTime, ninetyTime, ninetyFiveTime,
|
|||
|
ninetyNineTime, sumCode301, sumCode302, timeCount, sumQPSRecent, QPSRecent int
|
|||
|
var mins, maxs []int
|
|||
|
|
|||
|
if len(reportGraphs) > 0 {
|
|||
|
for _, reportGraph := range reportGraphs {
|
|||
|
mins = append(mins, reportGraph.Min)
|
|||
|
maxs = append(maxs, reportGraph.Max)
|
|||
|
sumCount = sumCount + reportGraph.Count
|
|||
|
timeCount = reportGraph.Count * reportGraph.AvgTime
|
|||
|
sumTime = sumTime + timeCount
|
|||
|
sumError = sumError + reportGraph.Error
|
|||
|
sumQPS = sumQPS + reportGraph.QPS
|
|||
|
sumNetIo = sumNetIo + reportGraph.NetIo
|
|||
|
sumCodeEll = sumCodeEll + reportGraph.CodeEll
|
|||
|
sumCodeWll = sumCodeWll + reportGraph.CodeWll
|
|||
|
sumCodeWly = sumCodeWly + reportGraph.CodeWly
|
|||
|
sumCodeWle = sumCodeWle + reportGraph.CodeWle
|
|||
|
sumCodeWls = sumCodeWls + reportGraph.CodeWls
|
|||
|
sumCodeSll = sumCodeSll + reportGraph.CodeSll
|
|||
|
sumCodeSly = sumCodeSly + reportGraph.CodeSly
|
|||
|
sumCodeSls = sumCodeSls + reportGraph.CodeSls
|
|||
|
sumCodeKong = sumCodeKong + reportGraph.CodeKong
|
|||
|
sumCode301 = sumCode301 + reportGraph.Code301
|
|||
|
sumCode302 = sumCode302 + reportGraph.Code302
|
|||
|
sumCodeNonHTTP = sumCodeNonHTTP + reportGraph.CodeNonHTTP
|
|||
|
sumCodeOthers = sumCodeOthers + reportGraph.CodeOthers
|
|||
|
fiftyTime = fiftyTime + reportGraph.FiftyTime
|
|||
|
ninetyTime = ninetyTime + reportGraph.NinetyTime
|
|||
|
ninetyFiveTime = ninetyFiveTime + reportGraph.NinetyFiveTime
|
|||
|
ninetyNineTime = ninetyNineTime + reportGraph.NinetyNineTime
|
|||
|
}
|
|||
|
// 取最后 recent次统计的平均 qps,作为最近一段时间的qps
|
|||
|
recent := conf.Conf.Melloi.Recent
|
|||
|
if len(reportGraphs) > recent {
|
|||
|
for i := 1; i <= recent; i++ {
|
|||
|
sumQPSRecent += reportGraphs[len(reportGraphs)-i].QPS
|
|||
|
QPSRecent = sumQPSRecent / recent
|
|||
|
}
|
|||
|
} else {
|
|||
|
QPSRecent = sumQPS / len(reportGraphs)
|
|||
|
}
|
|||
|
if len(mins) != 0 {
|
|||
|
sort.Ints(mins)
|
|||
|
min = mins[0]
|
|||
|
sort.Ints(maxs)
|
|||
|
max = maxs[len(maxs)-1]
|
|||
|
}
|
|||
|
failPercentd := float64(sumError) * 100 / float64(sumCount)
|
|||
|
n10 := math.Pow10(3)
|
|||
|
fail := math.Trunc((failPercentd+0.5/n10)*n10) / n10
|
|||
|
failStr := strconv.FormatFloat(fail, 'f', -1, 64)
|
|||
|
failPercent := failStr + "%"
|
|||
|
num := len(reportGraphs)
|
|||
|
reportGraph = model.ReportGraph{
|
|||
|
TestName: reportGraphs[0].TestName, TestNameNick: reportGraphs[0].TestNameNick, Max: max, Min: min, Count: sumCount, Error: sumError,
|
|||
|
NetIo: sumNetIo / num, QPS: sumQPS / num, AvgTime: sumTime / sumCount, Ctime: reportGraphs[len(reportGraphs)-1].Ctime,
|
|||
|
CodeEll: sumCodeEll, CodeSll: sumCodeSll, CodeSly: sumCodeSly, CodeSls: sumCodeSls, CodeWll: sumCodeWll, CodeWly: sumCodeWly,
|
|||
|
CodeWle: sumCodeWle, CodeWls: sumCodeWls, CodeNonHTTP: sumCodeNonHTTP, CodeKong: sumCodeKong, CodeOthers: sumCodeOthers,
|
|||
|
FailPercent: failPercent, FiftyTime: fiftyTime / num, NinetyTime: ninetyTime / num, NinetyFiveTime: ninetyFiveTime / num,
|
|||
|
NinetyNineTime: ninetyNineTime / num, Code301: sumCode301, Code302: sumCode302, BeginTime: reportGraphs[0].Ctime, QpsRecent: QPSRecent,
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//addReGraphTimer add regraph timer
|
|||
|
func (s *Service) addReGraphTimer(c context.Context, addReGrapht model.AddReGraphTimer, res chan interface{}, timeout <-chan time.Time) {
|
|||
|
var (
|
|||
|
status = 1
|
|||
|
reportSummary model.ReportSummary
|
|||
|
testNamesd []string
|
|||
|
podNames []string
|
|||
|
beginTimed string
|
|||
|
afterTimed string
|
|||
|
beginTime = addReGrapht.BeginTime
|
|||
|
testNames = addReGrapht.TestNames
|
|||
|
jobName = addReGrapht.JobName
|
|||
|
token = addReGrapht.Token
|
|||
|
testNameNicks = addReGrapht.TestNameNicks
|
|||
|
RetMap *model.PaasJobQueryStatus
|
|||
|
scriptID = addReGrapht.ScriptID
|
|||
|
reportSuID = addReGrapht.ReportSuID
|
|||
|
ptestJobs []*model.PtestJob
|
|||
|
err error
|
|||
|
btm time.Time
|
|||
|
firstRetMap *model.PaasJobQueryStatus
|
|||
|
reportGraphs []model.ReportGraph
|
|||
|
JSON []byte
|
|||
|
fusingList = addReGrapht.FusingList
|
|||
|
useBusiStopList = addReGrapht.UseBusiStopList
|
|||
|
busiStopPercentList = addReGrapht.BusiStopPercentList
|
|||
|
)
|
|||
|
timer := time.NewTicker(5 * time.Second)
|
|||
|
done := make(chan bool, 1)
|
|||
|
num := 1
|
|||
|
go func() {
|
|||
|
defer close(res)
|
|||
|
a := 1
|
|||
|
for {
|
|||
|
if btm, err = time.Parse("2006-01-02 15:04:05", beginTime); err != nil {
|
|||
|
timeout = time.After(time.Until(time.Now().Add(1 * time.Second)))
|
|||
|
return
|
|||
|
}
|
|||
|
select {
|
|||
|
case <-timer.C:
|
|||
|
elapsedTime := (num - 1) * 5
|
|||
|
//实时当前任务的所有容器
|
|||
|
if ptestJobs, err = s.QueryOrStopAllPtestByJobName(context.TODO(), reportSuID, false, 3); err != nil {
|
|||
|
log.Error("get all Job err (%v)", err)
|
|||
|
}
|
|||
|
//遍历容器,并查询每个容器的cpu
|
|||
|
if len(ptestJobs) > 0 {
|
|||
|
for _, ptestJob := range ptestJobs {
|
|||
|
if RetMap, err = s.dao.Job(c, token, ptestJob.JobName); err != nil {
|
|||
|
log.Error("get job info err (%v)", err)
|
|||
|
}
|
|||
|
if RetMap != nil && len(RetMap.Data.Pods) > 0 {
|
|||
|
for _, pod := range RetMap.Data.Pods {
|
|||
|
podNames = append(podNames, pod.Name)
|
|||
|
log.Info("containerID :(%s)", pod.ContainerID)
|
|||
|
go s.addJobCPU(context.TODO(), pod, scriptID, reportSuID, elapsedTime, ptestJob.JobName)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
log.Info("podName :(%s)", podNames)
|
|||
|
if firstRetMap, err = s.dao.Job(c, token, jobName); err != nil {
|
|||
|
log.Error("查询容器状态 error-------(%v)", err)
|
|||
|
//接口报错,则删除所有压测容器
|
|||
|
timeout = time.After(time.Until(time.Now().Add(1 * time.Second)))
|
|||
|
return
|
|||
|
}
|
|||
|
if JSON, err = json.Marshal(firstRetMap); err != nil {
|
|||
|
timeout = time.After(time.Until(time.Now().Add(1 * time.Second)))
|
|||
|
}
|
|||
|
result := string(JSON)
|
|||
|
log.Info("查询容器状态:(%s)", result)
|
|||
|
if firstRetMap.Status == 400 {
|
|||
|
status = 3
|
|||
|
timeout = time.After(time.Until(time.Now().Add(1 * time.Second)))
|
|||
|
}
|
|||
|
if firstRetMap.Status == 200 && firstRetMap.Data.ActiveNum == 1 {
|
|||
|
log.Info("第(%d)次同步数据", a)
|
|||
|
if num == 1 {
|
|||
|
log.Info("job 执行参数 testName:(%s), beginTime :(%s),elapsedTime :(%d), num: (%d)", testNames, beginTime, elapsedTime, num)
|
|||
|
for index, testName := range testNames {
|
|||
|
testNameNick := QueryTestNameNick(testName, testNameNicks)
|
|||
|
reportGraphAdd := model.ReportGraphAdd{
|
|||
|
JobName: jobName,
|
|||
|
TestName: testName,
|
|||
|
BeginTime: beginTime,
|
|||
|
AfterTime: beginTime,
|
|||
|
TestNameNick: testNameNick,
|
|||
|
PodNames: podNames,
|
|||
|
ElapsedTime: elapsedTime,
|
|||
|
ReportSuID: reportSuID,
|
|||
|
UseBusinessStop: addReGrapht.UseBusinessStop,
|
|||
|
BusinessStopPercent: addReGrapht.BusinessStopPercent,
|
|||
|
}
|
|||
|
if addReGrapht.TestType == model.PROTOCOL_SCENE {
|
|||
|
reportGraphAdd.Fusing = fusingList[index]
|
|||
|
reportGraphAdd.UseBusinessStop = useBusiStopList[index]
|
|||
|
reportGraphAdd.BusinessStopPercent = busiStopPercentList[index]
|
|||
|
} else {
|
|||
|
reportGraphAdd.Fusing = addReGrapht.Fusing
|
|||
|
}
|
|||
|
go s.addReportGraph(context.TODO(), reportGraphAdd)
|
|||
|
}
|
|||
|
} else {
|
|||
|
for i := 1; i <= num-1; i++ {
|
|||
|
btm = btm.Add(time.Second * 5)
|
|||
|
aft := btm.Add(time.Second * 2)
|
|||
|
beginTimed = btm.Format("2006-01-02 15:04:05")
|
|||
|
afterTimed = aft.Format("2006-01-02 15:04:05")
|
|||
|
}
|
|||
|
log.Info("job 执行参数 testName:(%s),beginTime :(%s),elapsedTime :(%d)", testNames, beginTimed, elapsedTime)
|
|||
|
for index, testName := range testNames {
|
|||
|
testNameNick := QueryTestNameNick(testName, testNameNicks)
|
|||
|
reportGraphAdd := model.ReportGraphAdd{
|
|||
|
JobName: jobName,
|
|||
|
TestName: testName,
|
|||
|
BeginTime: beginTimed,
|
|||
|
AfterTime: afterTimed,
|
|||
|
TestNameNick: testNameNick,
|
|||
|
PodNames: podNames,
|
|||
|
ElapsedTime: elapsedTime,
|
|||
|
ReportSuID: reportSuID,
|
|||
|
UseBusinessStop: addReGrapht.UseBusinessStop,
|
|||
|
BusinessStopPercent: addReGrapht.BusinessStopPercent,
|
|||
|
}
|
|||
|
if addReGrapht.TestType == model.PROTOCOL_SCENE {
|
|||
|
reportGraphAdd.Fusing = fusingList[index]
|
|||
|
reportGraphAdd.UseBusinessStop = useBusiStopList[index]
|
|||
|
reportGraphAdd.BusinessStopPercent = busiStopPercentList[index]
|
|||
|
} else {
|
|||
|
reportGraphAdd.Fusing = addReGrapht.Fusing
|
|||
|
}
|
|||
|
go s.addReportGraph(context.TODO(), reportGraphAdd)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
podNames = []string{}
|
|||
|
if firstRetMap.Status == 200 && firstRetMap.Data.ActiveNum == 0 {
|
|||
|
timeout = time.After(time.Until(time.Now().Add(1 * time.Second)))
|
|||
|
}
|
|||
|
num++
|
|||
|
res <- a
|
|||
|
a++
|
|||
|
case <-timeout:
|
|||
|
close(done)
|
|||
|
log.Info("real stop time (%s)", time.Now().Format("2006-01-02 15:04:05"))
|
|||
|
// 关闭所有压测该项目或者接口的容器
|
|||
|
go s.QueryOrStopAllPtestByJobName(context.TODO(), reportSuID, true, status)
|
|||
|
if reportGraphs, err = s.dao.QueryReportGraph(testNameNicks); err != nil {
|
|||
|
log.Error("query reportGraphs error :(%v) ", err)
|
|||
|
return
|
|||
|
}
|
|||
|
for _, reportGraph := range reportGraphs {
|
|||
|
testNamesd = append(testNames, reportGraph.TestName)
|
|||
|
}
|
|||
|
// 如果reportGraphs 的成员都是同一个testName ,则执行如下代码,表示进行结果合并,生成 reportSummary
|
|||
|
if IsUniqObject(testNamesd) {
|
|||
|
if len(reportGraphs) > 0 {
|
|||
|
reportGraph := ReportGraphAvg(reportGraphs)
|
|||
|
reportSummary = model.ReportSummary{
|
|||
|
ID: reportSuID,
|
|||
|
TestName: reportGraph.TestName,
|
|||
|
TestNameNick: reportGraph.TestNameNick,
|
|||
|
Count: reportGraph.Count,
|
|||
|
Error: reportGraph.Error,
|
|||
|
QPS: reportGraph.QPS,
|
|||
|
AvgTime: reportGraph.AvgTime,
|
|||
|
NetIo: reportGraph.NetIo,
|
|||
|
Min: reportGraph.Min,
|
|||
|
Max: reportGraph.Max,
|
|||
|
}
|
|||
|
reportSummary.TestStatus = status
|
|||
|
} else {
|
|||
|
log.Info("sorry,your test duration is too short ..... ")
|
|||
|
reportSummary = model.ReportSummary{ID: reportSuID, TestStatus: 3}
|
|||
|
}
|
|||
|
s.dao.UpdateReportSummary(&reportSummary)
|
|||
|
}
|
|||
|
//场景压测、多个接口走该逻辑
|
|||
|
if !IsUniqObject(testNamesd) && len(testNameNicks) > 0 {
|
|||
|
if len(reportGraphs) > 0 {
|
|||
|
reportSummary = model.ReportSummary{ID: reportSuID, TestStatus: status}
|
|||
|
} else {
|
|||
|
reportSummary = model.ReportSummary{ID: reportSuID, TestStatus: 3}
|
|||
|
}
|
|||
|
}
|
|||
|
s.dao.UpdateReportSummary(&reportSummary)
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
}()
|
|||
|
<-done
|
|||
|
}
|
|||
|
|
|||
|
//addPtestJobHostIp add regraph timer
|
|||
|
func (s *Service) addPtestJobHostIp(c context.Context, addReGrapht model.AddReGraphTimer, res chan interface{}, timeout <-chan time.Time) {
|
|||
|
var (
|
|||
|
RetMap *model.PaasJobQueryStatus
|
|||
|
token = addReGrapht.Token
|
|||
|
err error
|
|||
|
ptestJobs []*model.PtestJob
|
|||
|
ptestJobsd []*model.PtestJob
|
|||
|
firstRetMap *model.PaasJobQueryStatus
|
|||
|
)
|
|||
|
timer := time.NewTicker(10 * time.Second)
|
|||
|
done := make(chan bool, 1)
|
|||
|
go func() {
|
|||
|
defer close(res)
|
|||
|
a := 1
|
|||
|
for {
|
|||
|
select {
|
|||
|
case <-timer.C:
|
|||
|
if firstRetMap, err = s.dao.Job(c, token, addReGrapht.JobName); err != nil {
|
|||
|
log.Error("查询容器状态 error-------(%v)", err)
|
|||
|
//接口报错,则删除所有压测容器
|
|||
|
return
|
|||
|
}
|
|||
|
if firstRetMap == nil || firstRetMap.Status == 400 || (firstRetMap.Status == 200 && firstRetMap.Data.ActiveNum == 0) {
|
|||
|
return
|
|||
|
}
|
|||
|
ptestJob := model.PtestJob{ReportSuID: addReGrapht.ReportSuID, Active: 1}
|
|||
|
if ptestJobs, err = s.dao.QueryPtestJob(&ptestJob); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
for _, job := range ptestJobs {
|
|||
|
if job.HostIP == "" || job.JobIP == "" || job.JobID == "" {
|
|||
|
ptestJobsd = append(ptestJobsd, job)
|
|||
|
}
|
|||
|
}
|
|||
|
if len(ptestJobsd) > 0 {
|
|||
|
for _, ptestJob := range ptestJobsd {
|
|||
|
//查询容器状态
|
|||
|
if RetMap, err = s.dao.Job(c, token, ptestJob.JobName); err != nil {
|
|||
|
log.Error("get job info err (%v)", err)
|
|||
|
}
|
|||
|
if RetMap != nil && len(RetMap.Data.Pods) > 0 {
|
|||
|
for _, pod := range RetMap.Data.Pods {
|
|||
|
ptestjo := model.PtestJob{ID: ptestJob.ID, HostIP: pod.HostIP, JobID: pod.ContainerID, JobIP: pod.IP}
|
|||
|
//更新容器hostIp
|
|||
|
s.dao.UpdatePtestJob(ptestjo)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
res <- a
|
|||
|
a++
|
|||
|
case <-timeout:
|
|||
|
close(done)
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
}()
|
|||
|
<-done
|
|||
|
}
|
|||
|
|
|||
|
//addJobCPU job cpu
|
|||
|
func (s *Service) addJobCPU(c context.Context, pod model.PodInfo, scriptID, reportSuID, elapsedTime int, jobName string) (err error) {
|
|||
|
|
|||
|
var (
|
|||
|
clientMoni = model.ClientMoni{
|
|||
|
ScriptID: scriptID,
|
|||
|
ReportSuID: reportSuID,
|
|||
|
JobName: jobName,
|
|||
|
JobNameAll: pod.Name,
|
|||
|
ElapsdTime: elapsedTime,
|
|||
|
}
|
|||
|
dockerStats *model.DockerStats
|
|||
|
CPUResult *model.PaasQueryJobCPUResult
|
|||
|
)
|
|||
|
//首先查我们自己的容器cpu 获取服务
|
|||
|
if pod.ContainerID != "" {
|
|||
|
if dockerStats, err = s.QueryJobCPUByEP(context.TODO(), pod.ContainerID, pod.HostIP); err != nil {
|
|||
|
log.Error("query CPU err ...(%s)", err)
|
|||
|
}
|
|||
|
if dockerStats != nil && dockerStats.CPU != "" {
|
|||
|
cpu := strings.Replace(dockerStats.CPU, "%", "", 1)
|
|||
|
cpufloat, _ := strconv.ParseFloat(cpu, 32)
|
|||
|
cpuFinal := cpufloat
|
|||
|
cpuString := strconv.FormatFloat(cpuFinal, 'f', -1, 32)
|
|||
|
clientMoni.CPUUsed = cpuString
|
|||
|
}
|
|||
|
if dockerStats == nil || dockerStats.CPU == "" {
|
|||
|
//如果我们的服务挂了,就查 moni
|
|||
|
if CPUResult, err = s.QueryJobCPU(context.TODO(), pod.Name); err != nil {
|
|||
|
log.Error("query client cpu err(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
if len(CPUResult.Data) > 0 {
|
|||
|
for _, data := range CPUResult.Data {
|
|||
|
if len(data.Value) > 1 {
|
|||
|
clientMoni.CPUUsed = data.Value[1].(string)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//cpu 信息记录到数据库
|
|||
|
if _, err = s.AddClientMoni(&clientMoni); err != nil {
|
|||
|
log.Error("add ClientMoni err(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//addReportGraph add reportGraph
|
|||
|
func (s *Service) addReportGraph(c context.Context, reportGraphAdd model.ReportGraphAdd) {
|
|||
|
var (
|
|||
|
sumTime, sumQPS, sumNetIo, sumCodeEll, sumCodeWll, sumCodeWly, sumCodeWle, sumCodeWls, sumCodeSll, sumCodeSly, sumCodeSls,
|
|||
|
sumCodeKong, sumCodeNonHTTP, sumCodeOthers, sumCount, sumError, sumThreads, fiftyTime, ninetyTime, ninetyFiveTime,
|
|||
|
timeCount, ninetyNineTime, sumCode301, sumCode302 int
|
|||
|
mins, maxs []int
|
|||
|
reportTimelys []*model.ReportTimely
|
|||
|
err error
|
|||
|
)
|
|||
|
busiStopPerc := reportGraphAdd.BusinessStopPercent
|
|||
|
if reportTimelys, err = s.dao.QueryReTimely(reportGraphAdd.TestName, reportGraphAdd.BeginTime, reportGraphAdd.AfterTime, reportGraphAdd.PodNames); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
log.Info("------reportTimelys:(%v)", reportTimelys)
|
|||
|
if len(reportTimelys) > 0 {
|
|||
|
for _, reportTimely := range reportTimelys {
|
|||
|
mins = append(mins, reportTimely.Min)
|
|||
|
maxs = append(maxs, reportTimely.Max)
|
|||
|
sumCount = sumCount + reportTimely.Count
|
|||
|
//计算一个容器的接口响应总时间
|
|||
|
timeCount = reportTimely.Count * reportTimely.AvgTime
|
|||
|
//计算所有容器的接口响应时间
|
|||
|
sumTime = sumTime + timeCount
|
|||
|
sumQPS = sumQPS + reportTimely.QPS
|
|||
|
sumError = sumError + reportTimely.Error
|
|||
|
sumNetIo = sumNetIo + reportTimely.NetIo
|
|||
|
sumCodeEll = sumCodeEll + reportTimely.CodeEll
|
|||
|
sumCodeWll = sumCodeWll + reportTimely.CodeWll
|
|||
|
sumCodeWly = sumCodeWly + reportTimely.CodeWly
|
|||
|
sumCodeWle = sumCodeWle + reportTimely.CodeWle
|
|||
|
sumCodeWls = sumCodeWls + reportTimely.CodeWls
|
|||
|
sumCodeSll = sumCodeSll + reportTimely.CodeSll
|
|||
|
sumCodeSly = sumCodeSly + reportTimely.CodeSly
|
|||
|
sumCodeSls = sumCodeSls + reportTimely.CodeSls
|
|||
|
sumCodeKong = sumCodeKong + reportTimely.CodeKong
|
|||
|
sumCodeNonHTTP = sumCodeNonHTTP + reportTimely.CodeNonHTTP
|
|||
|
sumCodeOthers = sumCodeOthers + reportTimely.CodeOthers
|
|||
|
sumCode301 = sumCode301 + reportTimely.Code301
|
|||
|
sumCode302 = sumCode302 + reportTimely.Code302
|
|||
|
sumThreads = sumThreads + reportTimely.ThreadsSum
|
|||
|
fiftyTime = fiftyTime + reportTimely.FiftyTime
|
|||
|
ninetyTime = ninetyTime + reportTimely.NinetyTime
|
|||
|
ninetyFiveTime = ninetyFiveTime + reportTimely.NinetyFiveTime
|
|||
|
ninetyNineTime = ninetyNineTime + reportTimely.NinetyNineTime
|
|||
|
}
|
|||
|
sort.Ints(mins)
|
|||
|
min := mins[0]
|
|||
|
sort.Ints(maxs)
|
|||
|
max := maxs[len(maxs)-1]
|
|||
|
log.Info("test_nick_name ----- :(%s)", reportGraphAdd.TestNameNick)
|
|||
|
reportGraph := model.ReportGraph{
|
|||
|
TestName: reportGraphAdd.TestName, TestNameNick: reportGraphAdd.TestNameNick,
|
|||
|
Count: sumCount,
|
|||
|
QPS: sumQPS,
|
|||
|
Error: sumError,
|
|||
|
AvgTime: sumTime / sumCount,
|
|||
|
NetIo: sumNetIo,
|
|||
|
Min: min,
|
|||
|
Max: max,
|
|||
|
ElapsdTime: reportGraphAdd.ElapsedTime,
|
|||
|
CodeEll: sumCodeEll,
|
|||
|
CodeWll: sumCodeWll,
|
|||
|
CodeWly: sumCodeWly,
|
|||
|
CodeWle: sumCodeWle,
|
|||
|
CodeWls: sumCodeWls,
|
|||
|
CodeSll: sumCodeSll,
|
|||
|
CodeSly: sumCodeSly,
|
|||
|
CodeSls: sumCodeSls,
|
|||
|
CodeKong: sumCodeKong,
|
|||
|
CodeNonHTTP: sumCodeNonHTTP,
|
|||
|
CodeOthers: sumCodeOthers,
|
|||
|
ThreadsSum: sumThreads,
|
|||
|
FiftyTime: fiftyTime / len(reportTimelys),
|
|||
|
NinetyTime: ninetyTime / len(reportTimelys),
|
|||
|
NinetyFiveTime: ninetyFiveTime / len(reportTimelys),
|
|||
|
NinetyNineTime: ninetyNineTime / len(reportTimelys),
|
|||
|
Code301: sumCode301,
|
|||
|
Code302: sumCode302,
|
|||
|
}
|
|||
|
suCodeRate, suBusinessRate := CalcuSuccess(reportGraph)
|
|||
|
if reportGraphAdd.Fusing == 0 {
|
|||
|
reportGraphAdd.Fusing = conf.Conf.Melloi.DefaultFusing
|
|||
|
}
|
|||
|
//压测熔断
|
|||
|
//使用业务熔断,只要http code 和 业务断言错误满足一条阈值,则熔断
|
|||
|
if reportGraphAdd.UseBusinessStop {
|
|||
|
if busiStopPerc == 0 {
|
|||
|
busiStopPerc = conf.Conf.Melloi.DefaultBusinessRate
|
|||
|
}
|
|||
|
if suCodeRate < reportGraphAdd.Fusing || suBusinessRate < busiStopPerc {
|
|||
|
log.Info("接口失败率超过设置阈值,执行自动熔断,jobName :(%s)", reportGraphAdd.JobName)
|
|||
|
if _, err = s.DeleteJob(c, reportGraphAdd.JobName); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
reportsu := model.ReportSummary{ID: reportGraphAdd.ReportSuID, IsFusing: true, BusinessValue: busiStopPerc, UseBusinessStop: reportGraphAdd.UseBusinessStop,
|
|||
|
FusingTestName: reportGraphAdd.TestName, SuccessCodeRate: suCodeRate, SuccessBusinessRate: suBusinessRate, FusingValue: reportGraphAdd.Fusing}
|
|||
|
s.dao.UpdateReportSummary(&reportsu)
|
|||
|
}
|
|||
|
} else { //不使用业务熔断
|
|||
|
if suCodeRate < reportGraphAdd.Fusing {
|
|||
|
log.Info("接口失败率超过设置阈值,执行自动熔断,jobName :(%s)", reportGraphAdd.JobName)
|
|||
|
if _, err = s.DeleteJob(c, reportGraphAdd.JobName); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
reportsu := model.ReportSummary{ID: reportGraphAdd.ReportSuID, IsFusing: true, BusinessValue: busiStopPerc,
|
|||
|
FusingTestName: reportGraphAdd.TestName, SuccessCodeRate: suCodeRate, SuccessBusinessRate: suBusinessRate, FusingValue: reportGraphAdd.Fusing}
|
|||
|
s.dao.UpdateReportSummary(&reportsu)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
s.dao.AddReportGraph(&reportGraph)
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//CalcuSuccess calcu success
|
|||
|
func CalcuSuccess(reportGraph model.ReportGraph) (successCodeRate, successBusinessRate int) {
|
|||
|
success := reportGraph.CodeEll + reportGraph.CodeKong + reportGraph.Code301 + reportGraph.Code302
|
|||
|
successCodeRate = success * 100 / reportGraph.Count
|
|||
|
successBusinessRate = (reportGraph.Count - reportGraph.Error) * 100 / reportGraph.Count
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// DelReportSummary delete report summary
|
|||
|
func (s *Service) DelReportSummary(id int) error {
|
|||
|
return s.dao.DelReportSummary(id)
|
|||
|
}
|