summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts
new file mode 100644
index 000000000..7f3c9437d
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts
@@ -0,0 +1,196 @@
+import { Component, ElementRef, Input, OnChanges, OnInit, ViewChild } from '@angular/core';
+
+import { ChartDataSets, ChartOptions, ChartPoint, ChartType } from 'chart.js';
+import _ from 'lodash';
+import moment from 'moment';
+
+import { ChartTooltip } from '~/app/shared/models/chart-tooltip';
+
+@Component({
+ selector: 'cd-cephfs-chart',
+ templateUrl: './cephfs-chart.component.html',
+ styleUrls: ['./cephfs-chart.component.scss']
+})
+export class CephfsChartComponent implements OnChanges, OnInit {
+ @ViewChild('chartCanvas', { static: true })
+ chartCanvas: ElementRef;
+ @ViewChild('chartTooltip', { static: true })
+ chartTooltip: ElementRef;
+
+ @Input()
+ mdsCounter: any;
+
+ lhsCounter = 'mds_mem.ino';
+ rhsCounter = 'mds_server.handle_client_request';
+
+ chart: {
+ datasets: ChartDataSets[];
+ options: ChartOptions;
+ chartType: ChartType;
+ } = {
+ datasets: [
+ {
+ label: this.lhsCounter,
+ yAxisID: 'LHS',
+ data: [],
+ lineTension: 0.1
+ },
+ {
+ label: this.rhsCounter,
+ yAxisID: 'RHS',
+ data: [],
+ lineTension: 0.1
+ }
+ ],
+ options: {
+ title: {
+ text: '',
+ display: true
+ },
+ responsive: true,
+ maintainAspectRatio: false,
+ legend: {
+ position: 'top'
+ },
+ scales: {
+ xAxes: [
+ {
+ position: 'top',
+ type: 'time',
+ time: {
+ displayFormats: {
+ quarter: 'MMM YYYY'
+ }
+ },
+ ticks: {
+ maxRotation: 0
+ }
+ }
+ ],
+ yAxes: [
+ {
+ id: 'LHS',
+ type: 'linear',
+ position: 'left'
+ },
+ {
+ id: 'RHS',
+ type: 'linear',
+ position: 'right'
+ }
+ ]
+ },
+ tooltips: {
+ enabled: false,
+ mode: 'index',
+ intersect: false,
+ position: 'nearest',
+ callbacks: {
+ // Pick the Unix timestamp of the first tooltip item.
+ title: (tooltipItems, data): string => {
+ let ts = 0;
+ if (tooltipItems.length > 0) {
+ const item = tooltipItems[0];
+ const point = data.datasets[item.datasetIndex].data[item.index] as ChartPoint;
+ ts = point.x as number;
+ }
+ return ts.toString();
+ }
+ }
+ }
+ },
+ chartType: 'line'
+ };
+
+ ngOnInit() {
+ if (_.isUndefined(this.mdsCounter)) {
+ return;
+ }
+ this.setChartTooltip();
+ this.updateChart();
+ }
+
+ ngOnChanges() {
+ if (_.isUndefined(this.mdsCounter)) {
+ return;
+ }
+ this.updateChart();
+ }
+
+ private setChartTooltip() {
+ const chartTooltip = new ChartTooltip(
+ this.chartCanvas,
+ this.chartTooltip,
+ (tooltip: any) => tooltip.caretX + 'px',
+ (tooltip: any) => tooltip.caretY - tooltip.height - 23 + 'px'
+ );
+ chartTooltip.getTitle = (ts) => moment(ts, 'x').format('LTS');
+ chartTooltip.checkOffset = true;
+ const chartOptions: ChartOptions = {
+ title: {
+ text: this.mdsCounter.name
+ },
+ tooltips: {
+ custom: (tooltip) => chartTooltip.customTooltips(tooltip)
+ }
+ };
+ _.merge(this.chart, { options: chartOptions });
+ }
+
+ private updateChart() {
+ const chartDataSets: ChartDataSets[] = [
+ {
+ data: this.convertTimeSeries(this.mdsCounter[this.lhsCounter])
+ },
+ {
+ data: this.deltaTimeSeries(this.mdsCounter[this.rhsCounter])
+ }
+ ];
+ _.merge(this.chart, {
+ datasets: chartDataSets
+ });
+ this.chart.datasets = [...this.chart.datasets]; // Force angular to update
+ }
+
+ /**
+ * Convert ceph-mgr's time series format (list of 2-tuples
+ * with seconds-since-epoch timestamps) into what chart.js
+ * can handle (list of objects with millisecs-since-epoch
+ * timestamps)
+ */
+ private convertTimeSeries(sourceSeries: any) {
+ const data: any[] = [];
+ _.each(sourceSeries, (dp) => {
+ data.push({
+ x: dp[0] * 1000,
+ y: dp[1]
+ });
+ });
+
+ /**
+ * MDS performance counters chart is expecting the same number of items
+ * from each data series. Since in deltaTimeSeries we are ignoring the first
+ * element, we will do the same here.
+ */
+ data.shift();
+
+ return data;
+ }
+
+ private deltaTimeSeries(sourceSeries: any) {
+ let i;
+ let prev = sourceSeries[0];
+ const result = [];
+ for (i = 1; i < sourceSeries.length; i++) {
+ const cur = sourceSeries[i];
+
+ result.push({
+ x: cur[0] * 1000,
+ y: cur[1] - prev[1]
+ });
+
+ prev = cur;
+ }
+ return result;
+ }
+}