Browse Source

feat(monitors): Aggregate duration graph (#40008)

Rendering the data from this PR:
https://github.com/getsentry/sentry/pull/39651


<img width="1199" alt="image"
src="https://user-images.githubusercontent.com/9372512/196550216-89cd0f40-9b3a-409b-b710-d5126a506b14.png">
David Wang 2 years ago
parent
commit
7a28bc4ef2

+ 14 - 10
static/app/components/charts/miniBarChart.tsx

@@ -71,6 +71,19 @@ interface Props extends Omit<ChartProps, 'css' | 'colors' | 'series' | 'height'>
   utc?: boolean;
 }
 
+export function getYAxisMaxFn(height: number) {
+  return (value: {max: number; min: number}) => {
+    // This keeps small datasets from looking 'scary'
+    // by having full bars for < 10 values.
+    if (value.max < 10) {
+      return 10;
+    }
+    // Adds extra spacing at the top of the chart canvas, ensuring the series doesn't hit the ceiling, leaving more empty space.
+    // When the user hovers over an empty space, a tooltip with all series information is displayed.
+    return (value.max * (height + 10)) / height;
+  };
+}
+
 function MiniBarChart({
   emphasisColors,
   series,
@@ -148,16 +161,7 @@ function MiniBarChart({
         : undefined,
     },
     yAxis: {
-      max(value: {max: number; min: number}) {
-        // This keeps small datasets from looking 'scary'
-        // by having full bars for < 10 values.
-        if (value.max < 10) {
-          return 10;
-        }
-        // Adds extra spacing at the top of the chart canvas, ensuring the series doesn't hit the ceiling, leaving more empty space.
-        // When the user hovers over an empty space, a tooltip with all series information is displayed.
-        return (value.max * (height + 10)) / height;
-      },
+      max: getYAxisMaxFn(height),
       splitLine: {
         show: false,
       },

+ 38 - 2
static/app/views/monitors/monitorStats.tsx

@@ -1,4 +1,7 @@
-import MiniBarChart from 'sentry/components/charts/miniBarChart';
+import type {LineSeriesOption, YAXisComponentOption} from 'echarts';
+
+import MiniBarChart, {getYAxisMaxFn} from 'sentry/components/charts/miniBarChart';
+import LineSeries from 'sentry/components/charts/series/lineSeries';
 import EmptyMessage from 'sentry/components/emptyMessage';
 import {Panel, PanelBody} from 'sentry/components/panels';
 import {t} from 'sentry/locale';
@@ -38,12 +41,15 @@ const MonitorStats = ({monitor}: Props) => {
   let emptyStats = true;
   const success = {
     seriesName: t('Successful'),
+    yAxisIndex: 0,
     data: [] as SeriesDataUnit[],
   };
   const failed = {
     seriesName: t('Failed'),
+    yAxisIndex: 0,
     data: [] as SeriesDataUnit[],
   };
+  const durationData = [] as [number, number][];
 
   data.stats?.forEach(p => {
     if (p.ok || p.error) {
@@ -52,9 +58,28 @@ const MonitorStats = ({monitor}: Props) => {
     const timestamp = p.ts * 1000;
     success.data.push({name: timestamp, value: p.ok});
     failed.data.push({name: timestamp, value: p.error});
+    durationData.push([timestamp, Math.trunc(p.duration)]);
   });
   const colors = [theme.green300, theme.red300];
 
+  const additionalSeries: LineSeriesOption[] = [
+    LineSeries({
+      name: t('Duration'),
+      data: durationData,
+      lineStyle: {color: theme.purple300, width: 2},
+      itemStyle: {color: theme.purple300},
+      yAxisIndex: 1,
+    }),
+  ];
+
+  const height = 150;
+  const yAxisOptions: YAXisComponentOption = {
+    max: getYAxisMaxFn(height),
+    splitLine: {
+      show: false,
+    },
+  };
+
   return renderComponent(
     <Panel>
       <PanelBody withPadding>
@@ -65,8 +90,19 @@ const MonitorStats = ({monitor}: Props) => {
             labelYAxisExtents
             stacked
             colors={colors}
-            height={150}
+            height={height}
             series={[success, failed]}
+            additionalSeries={additionalSeries}
+            yAxes={[
+              {...yAxisOptions, type: 'value'},
+              {
+                ...yAxisOptions,
+                type: 'value',
+                axisLabel: {
+                  formatter: '{value} ms',
+                },
+              },
+            ]}
           />
         ) : (
           <EmptyMessage

+ 1 - 0
static/app/views/monitors/types.tsx

@@ -26,6 +26,7 @@ export type Monitor = {
 };
 
 export type MonitorStat = {
+  duration: number;
   error: number;
   ok: number;
   ts: number;