Browse Source

feat(profiling): Add profile.id column to discover (#43909)

This exposes the profile.id column in discover to query/search on.
Tony Xiao 2 years ago
parent
commit
5eed07ecb5

+ 12 - 0
static/app/utils/discover/fieldRenderers.tsx

@@ -310,6 +310,7 @@ type SpecialFields = {
   issue: SpecialField;
   'issue.id': SpecialField;
   minidump: SpecialField;
+  'profile.id': SpecialField;
   project: SpecialField;
   release: SpecialField;
   replayId: SpecialField;
@@ -460,6 +461,17 @@ const SPECIAL_FIELDS: SpecialFields = {
       );
     },
   },
+  'profile.id': {
+    sortField: 'profile.id',
+    renderFunc: data => {
+      const id: string | unknown = data?.['profile.id'];
+      if (typeof id !== 'string') {
+        return emptyValue;
+      }
+
+      return <Container>{getShortEventId(id)}</Container>;
+    },
+  },
   issue: {
     sortField: null,
     renderFunc: (data, {organization}) => {

+ 3 - 0
static/app/utils/discover/fields.tsx

@@ -630,6 +630,9 @@ export const TRACING_FIELDS = [
   SPAN_OP_RELATIVE_BREAKDOWN_FIELD,
 ];
 
+// This list contains fields/functions that are available with profiling feature.
+export const PROFILING_FIELDS: string[] = [FieldKey.PROFILE_ID];
+
 export const MEASUREMENT_PATTERN = /^measurements\.([a-zA-Z0-9-_.]+)$/;
 export const SPAN_OP_BREAKDOWN_PATTERN = /^spans\.([a-zA-Z0-9-_.]+)$/;
 

+ 8 - 0
static/app/utils/fields/index.ts

@@ -69,6 +69,7 @@ export enum FieldKey {
   OS_KERNEL_VERSION = 'os.kernel_version',
   PLATFORM = 'platform',
   PLATFORM_NAME = 'platform.name',
+  PROFILE_ID = 'profile.id',
   PROJECT = 'project',
   RELEASE = 'release',
   RELEASE_BUILD = 'release.build',
@@ -715,6 +716,11 @@ const EVENT_FIELD_DEFINITIONS: Record<AllEventFieldKeys, FieldDefinition> = {
     kind: FieldKind.FIELD,
     valueType: FieldValueType.STRING,
   },
+  [FieldKey.PROFILE_ID]: {
+    desc: t('The ID of an associated profile'),
+    kind: FieldKind.FIELD,
+    valueType: FieldValueType.STRING,
+  },
   [FieldKey.PROJECT]: {
     kind: FieldKind.FIELD,
     valueType: FieldValueType.STRING,
@@ -1070,6 +1076,8 @@ export const DISCOVER_FIELDS = [
   FieldKey.TRACE_SPAN,
   FieldKey.TRACE_PARENT_SPAN,
 
+  FieldKey.PROFILE_ID,
+
   // Meta field that returns total count, usually for equations
   FieldKey.TOTAL_COUNT,
 

+ 20 - 0
static/app/views/discover/table/tableView.tsx

@@ -42,6 +42,7 @@ import {
   generateEventSlug,
 } from 'sentry/utils/discover/urls';
 import ViewReplayLink from 'sentry/utils/discover/viewReplayLink';
+import {generateProfileFlamechartRoute} from 'sentry/utils/profiling/routes';
 import {decodeList} from 'sentry/utils/queryString';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import useProjects from 'sentry/utils/useProjects';
@@ -346,6 +347,25 @@ function TableView(props: TableViewProps) {
           </ViewReplayLink>
         );
       }
+    } else if (columnKey === 'profile.id') {
+      const projectSlug = dataRow.project || dataRow['project.name'];
+      const profileId = dataRow['profile.id'];
+
+      if (projectSlug && profileId) {
+        const target = generateProfileFlamechartRoute({
+          orgSlug: organization.slug,
+          projectSlug: String(projectSlug),
+          profileId: String(profileId),
+        });
+
+        cell = (
+          <StyledTooltip title={t('View Profile')}>
+            <StyledLink data-test-id="view-profile" to={target}>
+              {cell}
+            </StyledLink>
+          </StyledTooltip>
+        );
+      }
     }
 
     const topResultsIndicator =

+ 7 - 0
static/app/views/discover/utils.tsx

@@ -30,6 +30,7 @@ import {
   isMeasurement,
   isSpanOperationBreakdownField,
   measurementType,
+  PROFILING_FIELDS,
   TRACING_FIELDS,
 } from 'sentry/utils/discover/fields';
 import {DisplayModes, TOP_N} from 'sentry/utils/discover/types';
@@ -483,6 +484,12 @@ export function generateFieldOptions({
     fieldKeys = fieldKeys.filter(item => !TRACING_FIELDS.includes(item));
     functions = functions.filter(item => !TRACING_FIELDS.includes(item));
   }
+
+  // Strip profiling features if the org doesn't have access.
+  if (!organization.features.includes('profiling')) {
+    fieldKeys = fieldKeys.filter(item => !PROFILING_FIELDS.includes(item));
+  }
+
   const fieldOptions: Record<string, SelectValue<FieldValue>> = {};
 
   // Index items by prefixed keys as custom tags can overlap both fields and