Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 37 additions & 11 deletions static/app/views/alerts/rules/metric/eapField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import {
AggregationKey,
ALLOWED_EXPLORE_VISUALIZE_AGGREGATES,
NO_ARGUMENT_SPAN_AGGREGATES,
prettifyTagKey,
} from 'sentry/utils/fields';
import {Dataset, type EventTypes} from 'sentry/views/alerts/rules/metric/types';
import {getTraceItemTypeForDatasetAndEventType} from 'sentry/views/alerts/wizard/utils';
import {AttributeDetails} from 'sentry/views/explore/components/attributeDetails';
import {TypeBadge} from 'sentry/views/explore/components/typeBadge';
import {
DEFAULT_VISUALIZATION_FIELD,
updateVisualizeAggregate,
Expand Down Expand Up @@ -64,10 +67,11 @@ function EAPFieldWrapper({aggregate, onChange, eventTypes}: Props) {
}

function EAPField({aggregate, onChange, eventTypes}: Props) {
const traceItemType = getTraceItemTypeForDatasetAndEventType(
Dataset.EVENTS_ANALYTICS_PLATFORM,
eventTypes
);
const traceItemType =
getTraceItemTypeForDatasetAndEventType(
Dataset.EVENTS_ANALYTICS_PLATFORM,
eventTypes
) || TraceItemDataset.SPANS;
// We parse out the aggregation and field from the aggregate string.
// This only works for aggregates with <= 1 argument.
const {
Expand All @@ -78,10 +82,19 @@ function EAPField({aggregate, onChange, eventTypes}: Props) {
const {attributes: storedNumberTags} = useTraceItemAttributes('number');
const {attributes: storedStringTags} = useTraceItemAttributes('string');

const storedTags =
aggregation === AggregationKey.COUNT_UNIQUE ? storedStringTags : storedNumberTags;
const storedTags = useMemo(() => {
return aggregation === AggregationKey.COUNT_UNIQUE
? {...storedNumberTags, ...storedStringTags}
: storedNumberTags;
}, [aggregation, storedNumberTags, storedStringTags]);

const fieldsArray = Object.values(storedTags);
const fieldsArray = useMemo(() => {
return Object.values(storedTags).toSorted((a, b) => {
const aLabel = prettifyTagKey(a.key);
const bLabel = prettifyTagKey(b.key);
return aLabel.localeCompare(bLabel);
});
}, [storedTags]);

// When using the async variant of SelectControl, we need to pass in an option object instead of just the value
const [lockOptions, selectedOption] = useMemo(() => {
Expand Down Expand Up @@ -167,12 +180,25 @@ function EAPField({aggregate, onChange, eventTypes}: Props) {
searchText === '' || name.toLowerCase().includes(searchText.toLowerCase())
);

const options = filteredMeta.map(metric => {
return {label: metric.name, value: metric.key};
return filteredMeta.map(metric => {
return {
label: metric.name,
value: metric.key,
textValue: metric.key,
trailingItems: <TypeBadge kind={metric.kind} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={metric.key}
kind={metric.kind}
label={metric.name}
traceItemType={traceItemType}
/>
),
};
});
return options;
},
[fieldsArray]
[fieldsArray, traceItemType]
);

const operations =
Expand Down
10 changes: 5 additions & 5 deletions static/app/views/dashboards/datasetConfig/logs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const EAP_AGGREGATIONS = LOG_AGGREGATES.map(
parameters: [
{
kind: 'column',
columnTypes: ['string'],
columnTypes: ['number', 'string'],
defaultValue: 'message.template',
required: true,
},
Expand Down Expand Up @@ -299,14 +299,14 @@ function filterAggregateParams(option: FieldValueOption, fieldValue?: QueryField
return true; // COUNT() doesn't need parameters for logs
}

const expectedDataType =
const expectedDataTypes =
fieldValue?.kind === 'function' &&
fieldValue?.function[0] === AggregationKey.COUNT_UNIQUE
? 'string'
: 'number';
? new Set(['number', 'string'])
: new Set(['number']);

if ('dataType' in option.value.meta) {
return option.value.meta.dataType === expectedDataType;
return expectedDataTypes.has(option.value.meta.dataType);
}
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/dashboards/datasetConfig/spans.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const EAP_AGGREGATIONS = ALLOWED_EXPLORE_VISUALIZE_AGGREGATES.reduce(
parameters: [
{
kind: 'column',
columnTypes: ['string'],
columnTypes: ['number', 'string'],
defaultValue: 'span.op',
required: true,
},
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/explore/hooks/useVisualizeFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function getSupportedAttributes({
}

if (functionName === AggregationKey.COUNT_UNIQUE) {
return stringTags;
return {...numberTags, ...stringTags};
}

return numberTags;
Expand Down
8 changes: 5 additions & 3 deletions static/app/views/explore/logs/logsToolbar.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,11 @@ describe('LogsToolbar', () => {
await userEvent.click(screen.getByRole('option', {name: 'count unique'}));
await userEvent.click(screen.getByRole('button', {name: 'message'})); // this one isnt remapped for some reason
options = screen.getAllByRole('option');
expect(options).toHaveLength(2);
expect(options[0]).toHaveTextContent('message'); // this one isnt remapped for some reason
expect(options[1]).toHaveTextContent('severity');
expect(options).toHaveLength(4);
expect(options[0]).toHaveTextContent('barnumber');
expect(options[1]).toHaveTextContent('foonumber');
expect(options[2]).toHaveTextContent('message'); // this one isnt remapped for some reason
expect(options[3]).toHaveTextContent('severity');
await userEvent.click(screen.getByRole('option', {name: 'severity'}));
expect(router.location.query.aggregateField).toEqual(
[{groupBy: ''}, {yAxes: ['count_unique(severity)']}].map(aggregateField =>
Expand Down
147 changes: 107 additions & 40 deletions static/app/views/explore/logs/logsToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,17 +211,78 @@ function VisualizeDropdown({
const aggregateParam = visualize.parsedFunction?.arguments?.[0] ?? '';

const fieldOptions = useMemo(() => {
return aggregateFunction === AggregationKey.COUNT
? [{label: t('logs'), value: OurLogKnownFieldKey.MESSAGE}]
: aggregateFunction === AggregationKey.COUNT_UNIQUE
? sortedStringKeys.map(key => ({
label: prettifyTagKey(key),
if (aggregateFunction === AggregationKey.COUNT) {
return [{label: t('logs'), value: OurLogKnownFieldKey.MESSAGE}];
}

return aggregateFunction === AggregationKey.COUNT_UNIQUE
? [
...sortedNumberKeys.map(key => {
const label = prettifyTagKey(key);
return {
label,
value: key,
textValue: key,
trailingItems: <TypeBadge kind={FieldKind.MEASUREMENT} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={key}
kind={FieldKind.MEASUREMENT}
label={label}
traceItemType={TraceItemDataset.LOGS}
/>
),
};
}),
...sortedStringKeys.map(key => {
const label = prettifyTagKey(key);
return {
label,
value: key,
textValue: key,
trailingItems: <TypeBadge kind={FieldKind.TAG} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={key}
kind={FieldKind.TAG}
label={label}
traceItemType={TraceItemDataset.LOGS}
/>
),
};
}),
].toSorted((a, b) => {
const aLabel = prettifyTagKey(a.value);
const bLabel = prettifyTagKey(b.value);
if (aLabel < bLabel) {
return -1;
}

if (aLabel > bLabel) {
return 1;
}
return 0;
})
: sortedNumberKeys.map(key => {
const label = prettifyTagKey(key);
return {
label,
value: key,
}))
: sortedNumberKeys.map(key => ({
label: prettifyTagKey(key),
value: key,
}));
textValue: key,
trailingItems: <TypeBadge kind={FieldKind.MEASUREMENT} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={key}
kind={FieldKind.MEASUREMENT}
label={label}
traceItemType={TraceItemDataset.LOGS}
/>
),
};
});
}, [aggregateFunction, sortedStringKeys, sortedNumberKeys]);

const onChangeAggregate = useCallback(
Expand Down Expand Up @@ -274,36 +335,42 @@ function ToolbarGroupBy({numberTags, stringTags}: LogsToolbarProps) {
value: '',
textValue: '\u2014',
},
...Object.keys(numberTags ?? {}).map(key => ({
label: prettifyTagKey(key),
value: key,
textValue: key,
trailingItems: <TypeBadge kind={FieldKind.MEASUREMENT} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={key}
kind={FieldKind.MEASUREMENT}
label={key}
traceItemType={TraceItemDataset.LOGS}
/>
),
})),
...Object.keys(stringTags ?? {}).map(key => ({
label: prettifyTagKey(key),
value: key,
textValue: key,
trailingItems: <TypeBadge kind={FieldKind.TAG} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={key}
kind={FieldKind.TAG}
label={key}
traceItemType={TraceItemDataset.LOGS}
/>
),
})),
...Object.keys(numberTags ?? {}).map(key => {
const label = prettifyTagKey(key);
return {
label,
value: key,
textValue: key,
trailingItems: <TypeBadge kind={FieldKind.MEASUREMENT} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={key}
kind={FieldKind.MEASUREMENT}
label={label}
traceItemType={TraceItemDataset.LOGS}
/>
),
};
}),
...Object.keys(stringTags ?? {}).map(key => {
const label = prettifyTagKey(key);
return {
label,
value: key,
textValue: key,
trailingItems: <TypeBadge kind={FieldKind.TAG} />,
showDetailsInOverlay: true,
details: (
<AttributeDetails
column={key}
kind={FieldKind.TAG}
label={label}
traceItemType={TraceItemDataset.LOGS}
/>
),
};
}),
].toSorted((a, b) => {
const aLabel = prettifyTagKey(a.value);
const bLabel = prettifyTagKey(b.value);
Expand Down