Browse Source

feat(dynamic-sampling): Display stored spans (#80444)

Display stored spans in table and breakdown.

part of https://github.com/getsentry/projects/issues/354
ArthurKnaus 4 months ago
parent
commit
451171f4fa

+ 28 - 6
static/app/views/settings/dynamicSampling/projectsTable.tsx

@@ -32,6 +32,8 @@ interface Props extends Omit<React.ComponentProps<typeof StyledPanelTable>, 'hea
   onChange?: (projectId: string, value: string) => void;
 }
 
+const COLUMN_COUNT = 4;
+
 export function ProjectsTable({
   items,
   inactiveItems = [],
@@ -57,9 +59,10 @@ export function ProjectsTable({
       headers={[
         t('Project'),
         <SortableHeader type="button" key="spans" onClick={handleTableSort}>
-          {t('Spans')}
+          {t('Sent Spans')}
           <IconArrow direction={tableSort === 'desc' ? 'down' : 'up'} size="xs" />
         </SortableHeader>,
+        t('Stored Spans'),
         canEdit ? t('Target Rate') : t('Projected Rate'),
       ]}
     >
@@ -140,10 +143,11 @@ function SectionHeader({
         <StyledIconChevron direction={isExpanded ? 'down' : 'right'} />
         {title}
       </SectionHeaderCell>
-      {/* As the main element spans 3 grid colums we need to ensure that nth child css selectors of other elements
+      {/* As the main element spans COLUMN_COUNT grid colums we need to ensure that nth child css selectors of other elements
         remain functional by adding hidden elements */}
-      <div style={{display: 'none'}} />
-      <div style={{display: 'none'}} />
+      {Array.from({length: COLUMN_COUNT - 1}).map((_, i) => (
+        <div key={i} style={{display: 'none'}} />
+      ))}
     </Fragment>
   );
 }
@@ -243,6 +247,12 @@ const TableRow = memo(function TableRow({
     [onChange, project.id]
   );
 
+  const getStoredSpans = (rate: number) => {
+    return Math.floor((count * rate) / 100);
+  };
+  const storedSpans = getStoredSpans(Number(sampleRate));
+  const initialStoredSpans = getStoredSpans(Number(initialSampleRate));
+
   return (
     <Fragment key={project.slug}>
       <Cell>
@@ -274,6 +284,18 @@ const TableRow = memo(function TableRow({
         <FirstCellLine data-align="right">{formatAbbreviatedNumber(count)}</FirstCellLine>
         <SubSpans>{subSpansContent}</SubSpans>
       </Cell>
+      <Cell>
+        <FirstCellLine data-align="right">
+          {formatAbbreviatedNumber(storedSpans)}
+        </FirstCellLine>
+        <SubSpans>
+          {sampleRate !== initialSampleRate ? (
+            <SmallPrint>
+              {t('previous: %s', formatAbbreviatedNumber(initialStoredSpans))}
+            </SmallPrint>
+          ) : null}
+        </SubSpans>
+      </Cell>
       <Cell>
         <FirstCellLine>
           <Tooltip
@@ -302,7 +324,7 @@ const TableRow = memo(function TableRow({
 });
 
 const StyledPanelTable = styled(PanelTable)`
-  grid-template-columns: 1fr max-content max-content;
+  grid-template-columns: 1fr repeat(${COLUMN_COUNT - 1}, max-content);
 `;
 
 const SmallPrint = styled('span')`
@@ -337,7 +359,7 @@ const Cell = styled('div')`
 
 const SectionHeaderCell = styled('div')`
   display: flex;
-  grid-column: span 3;
+  grid-column: span ${COLUMN_COUNT};
   padding: ${space(1.5)};
   align-items: center;
   background: ${p => p.theme.backgroundSecondary};

+ 14 - 19
static/app/views/settings/dynamicSampling/samplingBreakdown.tsx

@@ -7,10 +7,8 @@ import {Tooltip} from 'sentry/components/tooltip';
 import {CHART_PALETTE} from 'sentry/constants/chartPalette';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
-import {
-  formatAbbreviatedNumber,
-  formatAbbreviatedNumberWithDynamicPrecision,
-} from 'sentry/utils/formatters';
+import {formatAbbreviatedNumber} from 'sentry/utils/formatters';
+import {formatNumberWithDynamicDecimalPoints} from 'sentry/utils/number/formatNumberWithDynamicDecimalPoints';
 import type {ProjectSampleCount} from 'sentry/views/settings/dynamicSampling/utils/useProjectSampleCounts';
 
 const ITEMS_TO_SHOW = 5;
@@ -68,7 +66,10 @@ export function SamplingBreakdown({sampleCounts, sampleRates, ...props}: Props)
 
   return (
     <div {...props}>
-      <Heading>{t('Breakdown of stored spans')}</Heading>
+      <Heading>
+        {t('Breakdown of stored spans')}
+        <SubText>{t('Total: %s', formatAbbreviatedNumber(total))}</SubText>
+      </Heading>
       <Breakdown>
         {topItems.map((item, index) => {
           return (
@@ -78,14 +79,8 @@ export function SamplingBreakdown({sampleCounts, sampleRates, ...props}: Props)
               title={
                 <LegendItem key={item.project.id}>
                   <ProjectBadge disableLink avatarSize={16} project={item.project} />
-                  {`${formatAbbreviatedNumberWithDynamicPrecision(getSpanPercent(item.sampledSpans))}%`}
-                  <SubText>
-                    {t(
-                      '%s of %s sampled spans',
-                      formatAbbreviatedNumber(item.sampledSpans),
-                      formatAbbreviatedNumber(total)
-                    )}
-                  </SubText>
+                  {`${formatNumberWithDynamicDecimalPoints(getSpanPercent(item.sampledSpans))}%`}
+                  <SubText>{formatAbbreviatedNumber(item.sampledSpans)}</SubText>
                 </LegendItem>
               }
               skipWrapper
@@ -105,10 +100,8 @@ export function SamplingBreakdown({sampleCounts, sampleRates, ...props}: Props)
             title={
               <LegendItem>
                 <OthersBadge />
-                {`${formatAbbreviatedNumberWithDynamicPrecision(otherPercent)}%`}
-                <SubText>
-                  {`${formatAbbreviatedNumber(otherSpanCount)} of ${formatAbbreviatedNumber(total)}`}
-                </SubText>
+                {`${formatNumberWithDynamicDecimalPoints(otherPercent)}%`}
+                <SubText>{formatAbbreviatedNumber(total)}</SubText>
               </LegendItem>
             }
             skipWrapper
@@ -127,14 +120,14 @@ export function SamplingBreakdown({sampleCounts, sampleRates, ...props}: Props)
           return (
             <LegendItem key={item.project.id}>
               <ProjectBadge avatarSize={16} project={item.project} />
-              {`${formatAbbreviatedNumberWithDynamicPrecision(getSpanPercent(item.sampledSpans))}%`}
+              {`${formatNumberWithDynamicDecimalPoints(getSpanPercent(item.sampledSpans))}%`}
             </LegendItem>
           );
         })}
         {hasOthers && (
           <LegendItem>
             <OthersBadge />
-            {`${formatAbbreviatedNumberWithDynamicPrecision(otherPercent)}%`}
+            {`${formatNumberWithDynamicDecimalPoints(otherPercent)}%`}
           </LegendItem>
         )}
       </Legend>
@@ -145,6 +138,8 @@ export function SamplingBreakdown({sampleCounts, sampleRates, ...props}: Props)
 const Heading = styled('h6')`
   margin-bottom: ${space(1)};
   font-size: ${p => p.theme.fontSizeMedium};
+  display: flex;
+  justify-content: space-between;
 `;
 
 const Breakdown = styled('div')`