Skip to content

Commit

Permalink
label comparison chart (#308)
Browse files Browse the repository at this point in the history
  • Loading branch information
ludeknovy authored Mar 11, 2023
1 parent 64ddd9b commit 75a1a3e
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 132 deletions.
90 changes: 90 additions & 0 deletions src/app/_services/chart-service-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { errorLineSettings, networkLineSettings, threadLineSettings, throughputLineSettings } from "../graphs/item-detail";
import { bytesToMbps } from "../item-detail/calculations";
import { Metrics } from "../item-detail/metrics";

export const getChartLines = (plot): ChartLines => {
const {
threads, overallTimeResponse,
overallThroughput, overAllFailRate, overAllNetworkV2,
responseTime, throughput, networkV2, minResponseTime, maxResponseTime, percentile90,
percentile95, percentile99, statusCodes, errorRate,
} = plot;

const threadLine = { ...threadLineSettings, name: "virtual users", data: threads, tooltip: { valueSuffix: "" } };
const errorLine = { ...errorLineSettings, ...overAllFailRate, tooltip: { valueSuffix: " %" } };
const throughputLine = { ...throughputLineSettings, ...overallThroughput, tooltip: { valueSuffix: " reqs/s" } };

const chartLines = {
overall: new Map(),
labels: new Map(),
statusCodes: new Map()
};

if (overAllNetworkV2) {
const networkMbps = overAllNetworkV2.data.map((_) => {
return [_[0], bytesToMbps(_[1])];
});
const networkLine = { ...networkLineSettings, data: networkMbps, tooltip: { valueSuffix: " mbps" } };
chartLines.overall.set(Metrics.Network, networkLine);
}

// not all reports have status code plot data
if (statusCodes) {
chartLines.statusCodes.set(Metrics.StatusCodeInTime, { data: statusCodes });
}

chartLines.overall.set(Metrics.ResponseTimeAvg, { ...overallTimeResponse, tooltip: { valueSuffix: " ms" } });
chartLines.overall.set(Metrics.Threads, threadLine);
chartLines.overall.set(Metrics.ErrorRate, errorLine);
chartLines.overall.set(Metrics.Throughput, throughputLine);

if (networkV2) {
const networkMbps = networkV2.map((_) => {
_.data = _.data.map(__ => [__[0], bytesToMbps(__[1])]);
return _;
});

chartLines.labels.set(Metrics.Network, networkMbps.map((label) => ({ ...label, suffix: " mbps" })));
}

if (minResponseTime) {
chartLines.labels.set(Metrics.ResponseTimeMin, minResponseTime.map((label) => ({ ...label, suffix: " ms" })));
}

if (maxResponseTime) {
chartLines.labels.set(Metrics.ResponseTimeMax, maxResponseTime.map((label) => ({ ...label, suffix: " ms" })));
}
if (percentile90) {
chartLines.labels.set(Metrics.ResponseTimeP90, percentile90.map((label) => ({ ...label, suffix: " ms" })));
}
if (percentile95) {
chartLines.labels.set(Metrics.ResponseTimeP95, percentile95.map((label) => ({ ...label, suffix: " ms" })));
}
if (percentile99) {
chartLines.labels.set(Metrics.ResponseTimeP99, percentile99.map((label) => ({ ...label, suffix: " ms" })));
}
if (errorRate) {
chartLines.labels.set(Metrics.ErrorRate, errorRate.map((label) => ({ ...label, suffix: " %" })));
}
chartLines.labels.set(Metrics.ResponseTimeAvg, responseTime.map((label) => ({ ...label, suffix: " ms" })));
chartLines.labels.set(Metrics.Throughput, throughput.map((label) => ({ ...label, suffix: " reqs/s" })));

return { chartLines };

};


export interface ChartLines {
chartLines: ChartLine;
}

export interface ChartLine {
labels: Map<string, LabelChartLine[]>;
overall: Map<string, { name: string, data: [] }>;
}

export interface LabelChartLine {
name: string
data: [],
suffix: string
}
16 changes: 16 additions & 0 deletions src/app/_services/comparison-chart.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from "@angular/core/testing";

import { ComparisonChartService } from "./comparison-chart.service";

describe("ComparisonChartService", () => {
let service: ComparisonChartService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ComparisonChartService);
});

it("should be created", () => {
expect(service).toBeTruthy();
});
});
45 changes: 45 additions & 0 deletions src/app/_services/comparison-chart.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { ChartLines, getChartLines } from "./chart-service-utils";

@Injectable({
providedIn: "root"
})
export class ComparisonChartService {


private plot$ = new BehaviorSubject<ChartLines>({ chartLines: null });
private histogramPlot$ = new BehaviorSubject<{ responseTimePerLabelDistribution: []}>(null);

private interval$ = new BehaviorSubject<string>(null);
selectedPlot$ = this.plot$.asObservable();
histogram$ = this.histogramPlot$.asObservable()


setInterval(interval) {
this.interval$.next(interval);
}

setHistogramPlot(plot) {
this.histogramPlot$.next(plot);
}

resetPlot() {
this.plot$.next(null)

}

setComparisonPlot(defaultPlot, extraPlots) {
this.interval$.subscribe(interval => {
let comparisonPlot = null
if (!interval || interval === "Auto") {
comparisonPlot = defaultPlot
} else {
const extraPlotIntervalData = extraPlots?.find(extraPlot => extraPlot.interval === interval)?.data
comparisonPlot = extraPlotIntervalData || defaultPlot
}
this.plot$.next(comparisonPlot ? getChartLines(comparisonPlot): null)
})

}
}
101 changes: 8 additions & 93 deletions src/app/_services/item-chart.service.ts
Original file line number Diff line number Diff line change
@@ -1,108 +1,23 @@
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { errorLineSettings, networkLineSettings, threadLineSettings, throughputLineSettings } from "../graphs/item-detail";
import { bytesToMbps } from "../item-detail/calculations";
import { Metrics } from "../item-detail/metrics";
import { ChartLines, getChartLines } from "./chart-service-utils";

@Injectable({
providedIn: "root"
})
export class ItemChartService {

private plot$ = new BehaviorSubject<ChartLines>({ chartLines: null });
selectedPlot$ = this.plot$.asObservable();

setCurrentPlot(plot) {
this.plot$.next(this.getChartLines(plot));
}


private getChartLines(plot): ChartLines {
const {
threads, overallTimeResponse,
overallThroughput, overAllFailRate, overAllNetworkV2,
responseTime, throughput, networkV2, minResponseTime, maxResponseTime, percentile90,
percentile95, percentile99, statusCodes, errorRate,
} = plot;

const threadLine = { ...threadLineSettings, name: "virtual users", data: threads, tooltip: { valueSuffix: "" } };
const errorLine = { ...errorLineSettings, ...overAllFailRate, tooltip: { valueSuffix: " %" } };
const throughputLine = { ...throughputLineSettings, ...overallThroughput, tooltip: { valueSuffix: " reqs/s" } };

const chartLines = {
overall: new Map(),
labels: new Map(),
statusCodes: new Map()
}

if (overAllNetworkV2) {
const networkMbps = overAllNetworkV2.data.map((_) => {
return [_[0], bytesToMbps(_[1])];
});
const networkLine = { ...networkLineSettings, data: networkMbps, tooltip: { valueSuffix: " mbps" } };
chartLines.overall.set(Metrics.Network, networkLine);
}

// not all reports have status code plot data
if (statusCodes) {
chartLines.statusCodes.set(Metrics.StatusCodeInTime, { data: statusCodes })
}

chartLines.overall.set(Metrics.ResponseTimeAvg, { ...overallTimeResponse, tooltip: { valueSuffix: " ms" } });
chartLines.overall.set(Metrics.Threads, threadLine);
chartLines.overall.set(Metrics.ErrorRate, errorLine);
chartLines.overall.set(Metrics.Throughput, throughputLine);

if (networkV2) {
const networkMbps = networkV2.map((_) => {
_.data = _.data.map(__ => [__[0], bytesToMbps(__[1])]);
return _;
});

chartLines.labels.set(Metrics.Network, networkMbps.map((label) => ({ ...label, suffix: " mbps" })));
}
private interval;

if (minResponseTime) {
chartLines.labels.set(Metrics.ResponseTimeMin, minResponseTime.map((label) => ({ ...label, suffix: " ms" })));
}

if (maxResponseTime) {
chartLines.labels.set(Metrics.ResponseTimeMax, maxResponseTime.map((label) => ({ ...label, suffix: " ms" })));
}
if (percentile90) {
chartLines.labels.set(Metrics.ResponseTimeP90, percentile90.map((label) => ({ ...label, suffix: " ms" })));
}
if (percentile95) {
chartLines.labels.set(Metrics.ResponseTimeP95, percentile95.map((label) => ({ ...label, suffix: " ms" })));
}
if (percentile99) {
chartLines.labels.set(Metrics.ResponseTimeP99, percentile99.map((label) => ({ ...label, suffix: " ms" })));
}
if (errorRate) {
chartLines.labels.set(Metrics.ErrorRate, errorRate.map((label) => ({ ...label, suffix: " %" })))
}
chartLines.labels.set(Metrics.ResponseTimeAvg, responseTime.map((label) => ({ ...label, suffix: " ms" })));
chartLines.labels.set(Metrics.Throughput, throughput.map((label) => ({ ...label, suffix: " reqs/s" })));
selectedPlot$ = this.plot$.asObservable();

return { chartLines }

setInterval(interval) {
this.interval = interval;
}


}


interface ChartLines {
chartLines: ChartLine
}

export interface ChartLine {
labels: Map<string, LabelChartLine[]>
overall: Map<string, { name: string, data: [] }>
}

export interface LabelChartLine {
name: string
data: [],
suffix: string
setCurrentPlot(plot) {
this.plot$.next(getChartLines(plot));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { customChartSettings } from "src/app/graphs/item-detail";
import * as Highcharts from "highcharts";
import { ItemsApiService } from "src/app/items-api.service";
import { AnalyzeChartService } from "../../analyze-chart.service";
import { ChartLine, ItemChartService } from "src/app/_services/item-chart.service";
import { ItemChartService } from "src/app/_services/item-chart.service";
import { ChartLine } from "../../_services/chart-service-utils";

@Component({
selector: "app-analyze-charts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Component, Input, OnInit } from "@angular/core";
import { ItemDataPlot, ItemExtraPlot } from "src/app/items.service.model";
import { ItemChartService } from "src/app/_services/item-chart.service";
import { interval } from "rxjs";
import { ComparisonChartService } from "../../_services/comparison-chart.service";

@Component({
selector: "app-chart-interval",
Expand All @@ -11,7 +13,10 @@ export class ChartIntervalComponent implements OnInit {

@Input() intervals: { defaultInterval: ItemDataPlot, extraIntervals: ItemExtraPlot[] }

constructor(private itemChartService: ItemChartService) {}
constructor(
private itemChartService: ItemChartService,
private comparisonChartService: ComparisonChartService
) {}

availableIntervals: string[]
defaultIntervalName = "Auto"
Expand All @@ -29,6 +34,8 @@ export class ChartIntervalComponent implements OnInit {
} else {
newPlotData = this.intervals.extraIntervals.find(interval => interval.interval === inputInterval)?.data
}
this.itemChartService.setInterval(interval)
this.comparisonChartService.setInterval(inputInterval)
this.itemChartService.setCurrentPlot(newPlotData)
}

Expand Down
9 changes: 7 additions & 2 deletions src/app/item-detail/label-chart/label-chart.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="card card-shadow" *ngIf="labelChartOptions">
<h6 class="card-header bg-transparent">
Label Chart - {{chartMetric}}
<span *ngIf="!labelCompareChartOptions" class="float-right">
<span class="float-right">


<button class="jtl-no-glow btn btn-sm jtl-ico-btn-light" (click)="collapseChart()"><i class="fa"
Expand All @@ -15,7 +15,7 @@ <h6 class="card-header bg-transparent">
class="arrow"></i></button>
<div class="dropdown-menu jtl-dropdown-control-menu" ngbDropdownMenu>
<button class="btn btn-sm" *ngFor="let _ of chartKeys" ngbDropdownItem
(click)="changeChart($event)">{{_}}</button>
(click)="changeChartAggregation($event)">{{_}}</button>
</div>
</div>
</span>
Expand All @@ -25,6 +25,11 @@ <h6 class="card-header bg-transparent">
<highcharts-chart #labelChart [Highcharts]="Highcharts" [options]="labelChartOptions" [callbackFunction]="chartCallback" [(update)]="updateLabelChartFlag"
class="highchart-chart"
style="width: 100%; height: 100%; display: block;"></highcharts-chart>
<div *ngIf="comparisonLabelChartOptions">
<highcharts-chart #labelComparisonChart [Highcharts]="Highcharts" [options]="comparisonLabelChartOptions" [callbackFunction]="comparisonChartCallback" [(update)]="updateLabelChartFlag"
class="highchart-chart"
style="width: 100%; height: 100%; display: block;"></highcharts-chart>
</div>
</div>
</div>

Expand Down
Loading

0 comments on commit 75a1a3e

Please sign in to comment.