Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Captain.B 2020-03-26 15:59:11 +08:00
commit 6da2645773
6 changed files with 212 additions and 9 deletions

View File

@ -8,6 +8,7 @@ import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ReportRequest; import io.metersphere.controller.request.ReportRequest;
import io.metersphere.dto.ReportDTO; import io.metersphere.dto.ReportDTO;
import io.metersphere.report.base.Errors;
import io.metersphere.report.base.RequestStatistics; import io.metersphere.report.base.RequestStatistics;
import io.metersphere.report.base.RequestStatisticsDTO; import io.metersphere.report.base.RequestStatisticsDTO;
import io.metersphere.service.ReportService; import io.metersphere.service.ReportService;
@ -59,5 +60,10 @@ public class ReportController {
return reportService.getReport(reportId); return reportService.getReport(reportId);
} }
@GetMapping("/content/errors/{reportId}")
public List<Errors> getReportErrors(@PathVariable String reportId) {
return reportService.getReportErrors(reportId);
}
} }

View File

@ -3,9 +3,11 @@ package io.metersphere.report;
import com.opencsv.bean.CsvToBean; import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder; import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy; import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import io.metersphere.report.base.Errors;
import io.metersphere.report.base.Metric; import io.metersphere.report.base.Metric;
import io.metersphere.report.base.RequestStatistics; import io.metersphere.report.base.RequestStatistics;
import io.metersphere.report.base.RequestStatisticsDTO; import io.metersphere.report.base.RequestStatisticsDTO;
import org.apache.commons.lang3.StringUtils;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
@ -79,7 +81,7 @@ public class JtlResolver {
Integer tp90 = elapsedList.size()*90/100; Integer tp90 = elapsedList.size()*90/100;
Integer tp95 = elapsedList.size()*95/100; Integer tp95 = elapsedList.size()*95/100;
Integer tp99 = elapsedList.size()*99/100; Integer tp99 = elapsedList.size()*99/100;
Long l = Long.valueOf(timestampList.get(index-1)) - Long.valueOf(timestampList.get(0)); Long l = Long.valueOf(timestampList.get(timestampList.size()-1)) - Long.valueOf(timestampList.get(0));
RequestStatistics requestStatistics = new RequestStatistics(); RequestStatistics requestStatistics = new RequestStatistics();
requestStatistics.setRequestLabel(label); requestStatistics.setRequestLabel(label);
@ -104,7 +106,7 @@ public class JtlResolver {
/** /**
* 所有的相同请求的bytes总和 / 1024 / 请求持续运行的时间=sum(bytes)/1024/total time * 所有的相同请求的bytes总和 / 1024 / 请求持续运行的时间=sum(bytes)/1024/total time
*/ */
// todo Avg Bandwidth(KBytes/s) // todo Avg Bandwidth(KBytes/s) 请求之间时间戳间隔l 可能为0
requestStatistics.setKbPerSec(String.format("%.2f",totalBytes*1.0/1024/(l*1.0/1000))); requestStatistics.setKbPerSec(String.format("%.2f",totalBytes*1.0/1024/(l*1.0/1000)));
requestStatisticsList.add(requestStatistics); requestStatisticsList.add(requestStatistics);
} }
@ -140,10 +142,40 @@ public class JtlResolver {
return statisticsDTO; return statisticsDTO;
} }
// Aggregate Report
public static RequestStatisticsDTO getRequestStatistics(String jtlString) { public static RequestStatisticsDTO getRequestStatistics(String jtlString) {
List<Metric> totalLines = resolver(jtlString); List<Metric> totalLines = resolver(jtlString);
Map<String, List<Metric>> map = totalLines.stream().collect(Collectors.groupingBy(Metric::getLabel)); Map<String, List<Metric>> map = totalLines.stream().collect(Collectors.groupingBy(Metric::getLabel));
return getOneRpsResult(map); return getOneRpsResult(map);
} }
// Errors
public static List<Errors> getErrorsList(String jtlString) {
List<Metric> totalLines = resolver(jtlString);
List<Metric> falseList = totalLines.stream().filter(metric -> StringUtils.equals("false", metric.getSuccess())).collect(Collectors.toList());
List<Errors> errorsList = new ArrayList<>();
Map<String, List<Metric>> collect = falseList.stream().collect(Collectors.groupingBy(JtlResolver::getResponseCodeAndFailureMessage));
Iterator<Map.Entry<String, List<Metric>>> iterator = collect.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, List<Metric>> next = iterator.next();
String key = next.getKey();
List<Metric> value = next.getValue();
Errors errors = new Errors();
errors.setErrorType(key);
errors.setErrorNumber(String.valueOf(value.size()));
Integer errorSize = value.size();
Integer errorAllSize = falseList.size();
Integer allSamples = totalLines.size();
DecimalFormat df = new DecimalFormat("0.00");
errors.setPrecentOfErrors(df.format((double)errorSize / errorAllSize * 100) + "%");
errors.setPrecentOfAllSamples(df.format((double)errorSize / allSamples * 100) + "%");
errorsList.add(errors);
}
return errorsList;
}
private static String getResponseCodeAndFailureMessage(Metric metric) {
return metric.getResponseCode() + "/" + metric.getResponseMessage();
}
} }

View File

@ -0,0 +1,41 @@
package io.metersphere.report.base;
public class Errors {
private String errorType;
private String errorNumber;
private String precentOfErrors;
private String precentOfAllSamples;
public String getErrorType() {
return errorType;
}
public void setErrorType(String errorType) {
this.errorType = errorType;
}
public String getErrorNumber() {
return errorNumber;
}
public void setErrorNumber(String errorNumber) {
this.errorNumber = errorNumber;
}
public String getPrecentOfErrors() {
return precentOfErrors;
}
public void setPrecentOfErrors(String precentOfErrors) {
this.precentOfErrors = precentOfErrors;
}
public String getPrecentOfAllSamples() {
return precentOfAllSamples;
}
public void setPrecentOfAllSamples(String precentOfAllSamples) {
this.precentOfAllSamples = precentOfAllSamples;
}
}

View File

@ -7,6 +7,7 @@ import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
import io.metersphere.controller.request.ReportRequest; import io.metersphere.controller.request.ReportRequest;
import io.metersphere.dto.ReportDTO; import io.metersphere.dto.ReportDTO;
import io.metersphere.report.JtlResolver; import io.metersphere.report.JtlResolver;
import io.metersphere.report.base.Errors;
import io.metersphere.report.base.RequestStatistics; import io.metersphere.report.base.RequestStatistics;
import io.metersphere.report.base.RequestStatisticsDTO; import io.metersphere.report.base.RequestStatisticsDTO;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -51,4 +52,11 @@ public class ReportService {
RequestStatisticsDTO requestStatistics = JtlResolver.getRequestStatistics(content); RequestStatisticsDTO requestStatistics = JtlResolver.getRequestStatistics(content);
return requestStatistics; return requestStatistics;
} }
public List<Errors> getReportErrors(String id) {
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent();
List<Errors> errors = JtlResolver.getErrorsList(content);
return errors;
}
} }

View File

@ -41,7 +41,7 @@
<ms-report-request-statistics :id="reportId"/> <ms-report-request-statistics :id="reportId"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('report.test_error_log')"> <el-tab-pane :label="$t('report.test_error_log')">
<ms-report-error-log /> <ms-report-error-log :id="reportId"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('report.test_log_details')"> <el-tab-pane :label="$t('report.test_log_details')">
<ms-report-log-details /> <ms-report-log-details />

View File

@ -1,32 +1,123 @@
<template> <template>
<div> <div>
<span class="table-title">Errors</span>
<el-table <el-table
:data="tableData" :data="tableData"
border border
stripe
style="width: 100%" style="width: 100%"
:default-sort = "{prop: 'elementLabel'}" :default-sort = "{prop: 'elementLabel'}"
> >
<el-table-column <el-table-column
prop="typeOfError" prop="errorType"
label="Type of Error" label="Type of Error"
sortable> sortable>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="numberOfErrors" prop="errorNumber"
label="Number of errors" label="Number of errors"
sortable> sortable>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="error" prop="precentOfErrors"
label="% in errors" label="% in errors"
sortable> sortable>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="allSamples" prop="precentOfAllSamples"
label="% in all samples" label="% in all samples"
sortable> sortable>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div style="margin-top: 40px;"></div>
<span class="table-title">Top 5 Errors by sampler </span>
<el-table
:data="tableData"
border
stripe
style="width: 100%"
>
<el-table-column
prop="errorType"
label="Sample"
width="400"
>
</el-table-column>
<el-table-column
prop="errorNumber"
label="#Samples"
width="120"
>
</el-table-column>
<el-table-column
prop="#Errors"
label="#Errors"
width="100"
>
</el-table-column>
<el-table-column
prop="Error"
label="Error"
width="400"
>
</el-table-column>
<el-table-column
prop="#Errors"
label="#Errors"
width="100"
>
</el-table-column>
<el-table-column
prop="Error"
label="Error"
width="400"
>
</el-table-column>
<el-table-column
prop="#Errors"
label="#Errors"
width="100"
>
</el-table-column>
<el-table-column
prop="Error"
label="Error"
width="400"
>
</el-table-column>
<el-table-column
prop="#Errors"
label="#Errors"
width="100"
>
</el-table-column>
<el-table-column
prop="Error"
label="Error"
width="400"
>
</el-table-column>
<el-table-column
prop="#Errors"
label="#Errors"
width="100"
>
</el-table-column>
<el-table-column
prop="Error"
label="Error"
width="400"
>
</el-table-column>
<el-table-column
prop="#Errors"
label="#Errors"
width="100"
>
</el-table-column>
</el-table>
</div> </div>
</template> </template>
@ -39,11 +130,36 @@
} }
}, },
methods: { methods: {
initTableData() {
this.$get("/report/content/errors/" + this.id, res => {
this.tableData = res.data;
})
}
},
created() {
this.initTableData();
},
props: ['id'],
watch: {
'$route'(to) {
if (to.name === "perReportView") {
let reportId = to.path.split('/')[4];
if(reportId){
this.$get("/report/content/errors/" + this.id, res => {
this.tableData = res.data;
})
}
}
}
} }
} }
</script> </script>
<style scoped> <style scoped>
.table-title {
font-size: 20px;
color: #8492a6;
display: block;
margin-bottom: 8px;
}
</style> </style>