Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
6da2645773
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue