]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Overview graph improvemntments 53090/head
authorcloudbehl <cloudbehl@gmail.com>
Thu, 10 Aug 2023 12:20:38 +0000 (17:50 +0530)
committercloudbehl <cloudbehl@gmail.com>
Wed, 23 Aug 2023 07:47:43 +0000 (13:17 +0530)
Fixes: https://tracker.ceph.com/issues/62367
Signed-off-by: cloudbehl <cloudbehl@gmail.com>
(cherry picked from commit 9fcc176162d39e5797042de301ffa0dea7f0254c)

13 files changed:
src/pybind/mgr/dashboard/frontend/cypress/e2e/ui/dashboard-v3.e2e-spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-time-selector/dashboard-time-selector.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-time-selector/dashboard-time-selector.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/enum/dashboard-promqls.enum.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/pipes/dimless-binary-per-second.pipe.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/pipes/dimless-binary.pipe.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/pipes/dimless.pipe.ts
src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss

index 80ea7c325fc29e1d1a35898b8aa625564076dd62..f6433aa3f073b42f6f6592fde92ad8235b68689c 100644 (file)
@@ -39,7 +39,7 @@ describe('Dashboard-v3 Main Page', () => {
     it('should verify that cards exist on dashboard in proper order', () => {
       // Ensures that cards are all displayed on the dashboard tab while being in the proper
       // order, checks for card title and position via indexing into a list of all cards.
-      const order = ['Details', 'Status', 'Capacity', 'Inventory', 'Cluster utilization'];
+      const order = ['Details', 'Status', 'Capacity', 'Inventory', 'Cluster Utilization'];
 
       for (let i = 0; i < order.length; i++) {
         dashboard.card(i).should('contain.text', order[i]);
index 6ac991fd58c5603ab6b23ad1b206437a035c057d..cb8b9dadb28376b79811933b5156d7b8b44a884a 100644 (file)
@@ -1,17 +1,33 @@
-<div class="row">
-  <div class="col-3 center-text">
+<div class="row mt-2">
+  <div class="col-3 d-flex flex-column align-self-center">
     <br>
-    <b class="chartTitle"
+    <b class="chartTitle pb-2"
        i18n>{{ chartTitle }}</b>
-    <br>
-    <span [ngbTooltip]="label"
-          i18n>{{currentData}} {{ currentDataUnits }}</span>
-    <br>
-    <span [ngbTooltip]="label2"
-          i18n>{{currentData2}} {{ currentDataUnits2 }}</span>
+    <div
+         i18n>
+      <div class="d-inline-flex align-items-center gap-1">
+        <div *ngIf="!maxValue"
+             class="blue-box">
+      </div>
+        <div *ngIf="label2">{{ label }}:
+        </div>
+        {{ currentData || 'N/A' }} {{ currentDataUnits }}
+        <div *ngIf="maxValue && currentData"> used of
+          {{ maxConvertedValue }} {{ maxConvertedValueUnits }}
+        </div>
+      </div>
+    </div>
+    <div *ngIf="label2"
+         i18n>
+      <div class="d-inline-flex align-items-center gap-1">
+        <div class="yellow-box"></div>
+        <div *ngIf="label2 !== chartTitle" >{{ label2 }}: </div>
+        <div>{{ currentData2 || 'N/A' }} {{ currentDataUnits2 }}</div>
+      </div>
+    </div>
   </div>
-  <div class="col-9">
-    <div class="chart">
+  <div class="col-9 d-flex flex-column">
+    <div class="chart mt-3">
       <canvas baseChart
               [datasets]="chartData.dataset"
               [options]="options"
index 12e9b9c1c6a5e1f2d1074f9e8a0ab110367b226d..02310e37e1b3512a653840257591b2bf42b439f4 100644 (file)
@@ -1,9 +1,19 @@
-.center-text {
-  margin-top: 1.2vw;
-  position: relative;
-}
+@use './src/styles/vendor/variables' as vv;
 
 .chart {
-  height: 8vh;
-  margin-top: 15px;
+  height: 9vh;
+}
+
+.blue-box {
+  background-color: vv.$chart-color-strong-blue;
+  border: 2px double vv.$chart-color-light-gray;
+  height: 13px;
+  width: 13px;
+}
+
+.yellow-box {
+  background-color: vv.$chart-color-orange;
+  border: 2px double vv.$chart-color-light-gray;
+  height: 13px;
+  width: 13px;
 }
index 35d8e571068cb61898dc68dc4cff1c0ab43b98e2..49e064a31ebeb63477e6038df48b22ff1914d75e 100644 (file)
@@ -37,26 +37,29 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
   currentData: number;
   currentDataUnits2?: string;
   currentData2?: number;
+  maxConvertedValue?: number;
+  maxConvertedValueUnits?: string;
 
   chartDataUnits: string;
-
   chartData: any = {
     dataset: [
       {
         label: '',
         data: [{ x: 0, y: 0 }],
-        tension: 0,
+        tension: 0.2,
         pointBackgroundColor: this.cssHelper.propertyValue('chart-color-strong-blue'),
         backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-blue'),
-        borderColor: this.cssHelper.propertyValue('chart-color-strong-blue')
+        borderColor: this.cssHelper.propertyValue('chart-color-strong-blue'),
+        borderWidth: 1
       },
       {
         label: '',
         data: [],
-        tension: 0,
+        tension: 0.2,
         pointBackgroundColor: this.cssHelper.propertyValue('chart-color-orange'),
-        backgroundColor: this.cssHelper.propertyValue('chart-color-yellow'),
-        borderColor: this.cssHelper.propertyValue('chart-color-orange')
+        backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-yellow'),
+        borderColor: this.cssHelper.propertyValue('chart-color-orange'),
+        borderWidth: 1
       }
     ]
   };
@@ -64,6 +67,7 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
   options: any = {
     responsive: true,
     maintainAspectRatio: false,
+    animation: false,
     elements: {
       point: {
         radius: 0
@@ -73,6 +77,7 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
       display: false
     },
     tooltips: {
+      mode: 'index',
       custom: function (tooltipModel: { x: number; y: number }) {
         tooltipModel.x = 10;
         tooltipModel.y = 0;
@@ -83,6 +88,16 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
       callbacks: {
         title: function (tooltipItem: any): any {
           return tooltipItem[0].xLabel;
+        },
+        label: (tooltipItems: any, data: any) => {
+          return (
+            ' ' +
+            data.datasets[tooltipItems.datasetIndex].label +
+            ' - ' +
+            tooltipItems.value +
+            ' ' +
+            this.chartDataUnits
+          );
         }
       }
     },
@@ -98,7 +113,7 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
             display: false
           },
           time: {
-            tooltipFormat: 'YYYY/MM/DD hh:mm:ss'
+            tooltipFormat: 'DD/MM/YYYY - HH:mm:ss'
           }
         }
       ],
@@ -109,7 +124,7 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
           },
           ticks: {
             beginAtZero: true,
-            maxTicksLimit: 3,
+            maxTicksLimit: 4,
             callback: (value: any) => {
               if (value === 0) {
                 return null;
@@ -168,17 +183,20 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
   }
 
   private updateChartData(): void {
+    this.chartData.dataset[0].label = this.label;
+    this.chartData.dataset[1].label = this.label2;
+    this.setChartTicks();
     if (this.data) {
-      this.setChartTicks();
       this.chartData.dataset[0].data = this.formatData(this.data);
-      this.chartData.dataset[0].label = this.label;
       [this.currentData, this.currentDataUnits] = this.convertUnits(
         this.data[this.data.length - 1][1]
       ).split(' ');
+      [this.maxConvertedValue, this.maxConvertedValueUnits] = this.convertUnits(
+        this.maxValue
+      ).split(' ');
     }
     if (this.data2) {
       this.chartData.dataset[1].data = this.formatData(this.data2);
-      this.chartData.dataset[1].label = this.label2;
       [this.currentData2, this.currentDataUnits2] = this.convertUnits(
         this.data2[this.data2.length - 1][1]
       ).split(' ');
@@ -204,13 +222,15 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
         dataWithUnits = this.numberFormatter.formatBytesFromTo(
           data,
           this.dataUnits,
-          this.chartDataUnits
+          this.chartDataUnits,
+          this.decimals
         );
       } else if (this.dataUnits === 'B/s') {
         dataWithUnits = this.numberFormatter.formatBytesPerSecondFromTo(
           data,
           this.dataUnits,
-          this.chartDataUnits
+          this.chartDataUnits,
+          this.decimals
         );
       } else if (this.dataUnits === 'ms') {
         dataWithUnits = this.numberFormatter.formatSecondsFromTo(
@@ -223,7 +243,8 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
         dataWithUnits = this.numberFormatter.formatUnitlessFromTo(
           data,
           this.dataUnits,
-          this.chartDataUnits
+          this.chartDataUnits,
+          this.decimals
         );
       }
     }
@@ -233,13 +254,13 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
   private convertUnits(data: any): any {
     let dataWithUnits: string = '';
     if (this.dataUnits === 'B') {
-      dataWithUnits = this.dimlessBinary.transform(data);
+      dataWithUnits = this.dimlessBinary.transform(data, this.decimals);
     } else if (this.dataUnits === 'B/s') {
-      dataWithUnits = this.dimlessBinaryPerSecond.transform(data);
+      dataWithUnits = this.dimlessBinaryPerSecond.transform(data, this.decimals);
     } else if (this.dataUnits === 'ms') {
       dataWithUnits = this.formatter.format_number(data, 1000, ['ms', 's'], this.decimals);
     } else {
-      dataWithUnits = this.dimlessPipe.transform(data);
+      dataWithUnits = this.dimlessPipe.transform(data, this.decimals);
     }
     return dataWithUnits;
   }
@@ -265,11 +286,7 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
     let maxValueDataUnits = '';
     let extraRoom = 1.2;
 
-    if (this.maxValue) {
-      extraRoom = 1.0;
-      [maxValue, maxValueDataUnits] = this.convertUnits(this.maxValue).split(' ');
-    } else if (this.data) {
-      extraRoom = 1.2;
+    if (this.data) {
       let maxValueData = Math.max(...this.data.map((values: any) => values[1]));
       if (this.data2) {
         let maxValueData2 = Math.max(...this.data2.map((values: any) => values[1]));
@@ -283,7 +300,6 @@ export class DashboardAreaChartComponent implements OnChanges, AfterViewInit {
     const yAxesTicks = this.chart.chart.options.scales.yAxes[0].ticks;
     yAxesTicks.suggestedMax = maxValue * extraRoom;
     yAxesTicks.suggestedMin = 0;
-    yAxesTicks.stepSize = Number((yAxesTicks.suggestedMax / 2).toFixed(0));
     yAxesTicks.callback = (value: any) => {
       if (value === 0) {
         return null;
index 3b0915232b665648cd791c380675ec81c662a82d..9e368efc7f0c90d7ef71841f7ea32e1b1ca66cc1 100644 (file)
@@ -26,35 +26,27 @@ export class DashboardTimeSelectorComponent {
       },
       {
         name: $localize`Last 30 minutes`,
-        value: this.timeToDate(30 * 60, 6)
+        value: this.timeToDate(30 * 60, 7)
       },
       {
         name: $localize`Last 1 hour`,
-        value: this.timeToDate(3600, 12)
+        value: this.timeToDate(3600, 14)
       },
       {
         name: $localize`Last 3 hours`,
-        value: this.timeToDate(3 * 3600, 36)
+        value: this.timeToDate(3 * 3600, 42)
       },
       {
         name: $localize`Last 6 hours`,
-        value: this.timeToDate(6 * 3600, 72)
+        value: this.timeToDate(6 * 3600, 84)
       },
       {
         name: $localize`Last 12 hours`,
-        value: this.timeToDate(12 * 3600, 144)
+        value: this.timeToDate(12 * 3600, 168)
       },
       {
         name: $localize`Last 24 hours`,
-        value: this.timeToDate(24 * 3600, 288)
-      },
-      {
-        name: $localize`Last 2 days`,
-        value: this.timeToDate(48 * 3600, 576)
-      },
-      {
-        name: $localize`Last 7 days`,
-        value: this.timeToDate(168 * 3600, 2016)
+        value: this.timeToDate(24 * 3600, 336)
       }
     ];
     this.time = this.times[3].value;
@@ -64,7 +56,7 @@ export class DashboardTimeSelectorComponent {
     this.selectedTime.emit(this.timeToDate(this.time.end - this.time.start, this.time.step));
   }
 
-  private timeToDate(secondsAgo: number, step: number): any {
+  public timeToDate(secondsAgo: number, step: number): any {
     const date: number = moment().unix() - secondsAgo;
     const dateNow: number = moment().unix();
     const formattedDate: any = {
index 61d36c7a2555ed9028996c0b2ca1daa873a8bc2d..b3baaf1117f16285772aec37f7c6347811fb3055 100644 (file)
       </li>
     </cd-card>
 
-    <cd-card cardTitle="Cluster utilization"
+    <cd-card cardTitle="Cluster Utilization"
              i18n-title
              class="col-sm-9 px-3 d-flex"
              aria-label="Cluster utilization card">
         <cd-dashboard-time-selector (selectedTime)="getPrometheusData($event)">
         </cd-dashboard-time-selector>
         <ng-container *ngIf="capacity">
-          <cd-dashboard-area-chart chartTitle="Used Capacity"
+          <cd-dashboard-area-chart chartTitle="Used Capacity (RAW)"
                                    [maxValue]="capacity.total_bytes"
                                    dataUnits="B"
                                    label="Used Capacity"
         </ng-container>
         <cd-dashboard-area-chart chartTitle="IOPS"
                                  dataUnits=""
-                                 label="OPS"
-                                 label2="IPS"
-                                 [data]="queriesResults.OPS"
-                                 [data2]="queriesResults.IPS">
+                                 decimals="0"
+                                 label="Reads"
+                                 label2="Writes"
+                                 [data]="queriesResults.READIOPS"
+                                 [data2]="queriesResults.WRITEIOPS">
         </cd-dashboard-area-chart>
-        <cd-dashboard-area-chart chartTitle="Latency"
+        <cd-dashboard-area-chart chartTitle="OSD Latencies"
                                  dataUnits="ms"
-                                 decimals="3"
-                                 label="Read"
-                                 label2="Write"
+                                 decimals="2"
+                                 label="Apply"
+                                 label2="Commit"
                                  [data]="queriesResults.READLATENCY"
                                  [data2]="queriesResults.WRITELATENCY">
         </cd-dashboard-area-chart>
         <cd-dashboard-area-chart chartTitle="Client Throughput"
                                  dataUnits="B/s"
-                                 label="Read"
-                                 label2="Write"
+                                 decimals="2"
+                                 label="Reads"
+                                 label2="Writes"
                                  [data]="queriesResults.READCLIENTTHROUGHPUT"
                                  [data2]="queriesResults.WRITECLIENTTHROUGHPUT">
         </cd-dashboard-area-chart>
         <cd-dashboard-area-chart chartTitle="Recovery Throughput"
                                  dataUnits="B/s"
+                                 decimals="2"
                                  label="Recovery Throughput"
                                  [data]="queriesResults.RECOVERYBYTES">
         </cd-dashboard-area-chart>
index a682d7e5d8e7210211be1cfe48137069e2666184..1d60926ffde5e723ef9030bfd538aa820495699a 100644 (file)
@@ -70,7 +70,7 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
   readonly lastHourDateObject = {
     start: moment().unix() - 3600,
     end: moment().unix(),
-    step: 12
+    step: 14
   };
 
   constructor(
index 3f76fa828f57e978b44d401b7f49317d5786c68a..515fefcdb6107ff88a496b55050c558b78593447 100644 (file)
@@ -1,7 +1,7 @@
 export enum Promqls {
   USEDCAPACITY = 'ceph_cluster_total_used_bytes',
-  IPS = 'sum(rate(ceph_osd_op_w_in_bytes[1m]))',
-  OPS = 'sum(rate(ceph_osd_op_r_out_bytes[1m]))',
+  WRITEIOPS = 'sum(rate(ceph_pool_wr[1m]))',
+  READIOPS = 'sum(rate(ceph_pool_rd[1m]))',
   READLATENCY = 'avg_over_time(ceph_osd_apply_latency_ms[1m])',
   WRITELATENCY = 'avg_over_time(ceph_osd_commit_latency_ms[1m])',
   READCLIENTTHROUGHPUT = 'sum(rate(ceph_pool_rd_bytes[1m]))',
index cbd57fd2643a7b92126d2cee2efe2ccc82306eed..7fdb304717bd557d1066a1576c1143a169e37de2 100644 (file)
@@ -8,17 +8,12 @@ import { FormatterService } from '../services/formatter.service';
 export class DimlessBinaryPerSecondPipe implements PipeTransform {
   constructor(private formatter: FormatterService) {}
 
-  transform(value: any): any {
-    return this.formatter.format_number(value, 1024, [
-      'B/s',
-      'KiB/s',
-      'MiB/s',
-      'GiB/s',
-      'TiB/s',
-      'PiB/s',
-      'EiB/s',
-      'ZiB/s',
-      'YiB/s'
-    ]);
+  transform(value: any, decimals: number = 1): any {
+    return this.formatter.format_number(
+      value,
+      1024,
+      ['B/s', 'KiB/s', 'MiB/s', 'GiB/s', 'TiB/s', 'PiB/s', 'EiB/s', 'ZiB/s', 'YiB/s'],
+      decimals
+    );
   }
 }
index cf5d2cdec24b13eff1c65f26fe7688e54c803c78..f4cfd259e77139a062a424dc8013193b9e1db32a 100644 (file)
@@ -8,17 +8,12 @@ import { FormatterService } from '../services/formatter.service';
 export class DimlessBinaryPipe implements PipeTransform {
   constructor(private formatter: FormatterService) {}
 
-  transform(value: any): any {
-    return this.formatter.format_number(value, 1024, [
-      'B',
-      'KiB',
-      'MiB',
-      'GiB',
-      'TiB',
-      'PiB',
-      'EiB',
-      'ZiB',
-      'YiB'
-    ]);
+  transform(value: any, decimals: number = 1): any {
+    return this.formatter.format_number(
+      value,
+      1024,
+      ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'],
+      decimals
+    );
   }
 }
index 1be11590dc4a7f980a78e03867301503c0fe3a53..a79942d6aaad49efc48281b2726af976dea10535 100644 (file)
@@ -8,7 +8,12 @@ import { FormatterService } from '../services/formatter.service';
 export class DimlessPipe implements PipeTransform {
   constructor(private formatter: FormatterService) {}
 
-  transform(value: any): any {
-    return this.formatter.format_number(value, 1000, ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']);
+  transform(value: any, decimals: number = 1): any {
+    return this.formatter.format_number(
+      value,
+      1000,
+      ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
+      decimals
+    );
   }
 }
index 4be14a898784f1e2c99dfddd6afe0c71d2b2c7d8..e9c8a595620a8be9e19435d98646115254e26c65 100644 (file)
@@ -94,6 +94,7 @@ $chart-danger: #c9190b !default;
 $chart-color-strong-blue: #0078c8 !default;
 $chart-color-translucent-blue: #0096dc80 !default;
 $chart-color-border: #00000020 !default;
+$chart-color-translucent-yellow: #ef923472 !default;
 
 // Typography