monitorStats.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import type {LineSeriesOption, YAXisComponentOption} from 'echarts';
  2. import MiniBarChart, {getYAxisMaxFn} from 'sentry/components/charts/miniBarChart';
  3. import LineSeries from 'sentry/components/charts/series/lineSeries';
  4. import EmptyMessage from 'sentry/components/emptyMessage';
  5. import {Panel, PanelBody} from 'sentry/components/panels';
  6. import {t} from 'sentry/locale';
  7. import {SeriesDataUnit} from 'sentry/types/echarts';
  8. import theme from 'sentry/utils/theme';
  9. import useApiRequests from 'sentry/utils/useApiRequests';
  10. import {Monitor, MonitorStat} from './types';
  11. type Props = {
  12. monitor: Monitor;
  13. };
  14. type State = {
  15. stats: MonitorStat[] | null;
  16. };
  17. const MonitorStats = ({monitor}: Props) => {
  18. const until = Math.floor(new Date().getTime() / 1000);
  19. const since = until - 3600 * 24 * 30;
  20. const {data, renderComponent} = useApiRequests<State>({
  21. endpoints: [
  22. [
  23. 'stats',
  24. `/monitors/${monitor.id}/stats/`,
  25. {
  26. query: {
  27. since: since.toString(),
  28. until: until.toString(),
  29. resolution: '1d',
  30. },
  31. },
  32. ],
  33. ],
  34. });
  35. let emptyStats = true;
  36. const success = {
  37. seriesName: t('Successful'),
  38. yAxisIndex: 0,
  39. data: [] as SeriesDataUnit[],
  40. };
  41. const failed = {
  42. seriesName: t('Failed'),
  43. yAxisIndex: 0,
  44. data: [] as SeriesDataUnit[],
  45. };
  46. const durationData = [] as [number, number][];
  47. data.stats?.forEach(p => {
  48. if (p.ok || p.error) {
  49. emptyStats = false;
  50. }
  51. const timestamp = p.ts * 1000;
  52. success.data.push({name: timestamp, value: p.ok});
  53. failed.data.push({name: timestamp, value: p.error});
  54. durationData.push([timestamp, Math.trunc(p.duration)]);
  55. });
  56. const colors = [theme.green300, theme.red300];
  57. const additionalSeries: LineSeriesOption[] = [
  58. LineSeries({
  59. name: t('Duration'),
  60. data: durationData,
  61. lineStyle: {color: theme.purple300, width: 2},
  62. itemStyle: {color: theme.purple300},
  63. yAxisIndex: 1,
  64. }),
  65. ];
  66. const height = 150;
  67. const yAxisOptions: YAXisComponentOption = {
  68. max: getYAxisMaxFn(height),
  69. splitLine: {
  70. show: false,
  71. },
  72. };
  73. return renderComponent(
  74. <Panel>
  75. <PanelBody withPadding>
  76. {!emptyStats ? (
  77. <MiniBarChart
  78. isGroupedByDate
  79. showTimeInTooltip
  80. labelYAxisExtents
  81. stacked
  82. colors={colors}
  83. height={height}
  84. series={[success, failed]}
  85. additionalSeries={additionalSeries}
  86. yAxes={[
  87. {...yAxisOptions, type: 'value'},
  88. {
  89. ...yAxisOptions,
  90. type: 'value',
  91. axisLabel: {
  92. formatter: '{value} ms',
  93. },
  94. },
  95. ]}
  96. />
  97. ) : (
  98. <EmptyMessage
  99. title={t('Nothing recorded in the last 30 days.')}
  100. description={t('All check-ins for this monitor.')}
  101. />
  102. )}
  103. </PanelBody>
  104. </Panel>
  105. );
  106. };
  107. export default MonitorStats;