Skip to content

Commit

Permalink
feat: show/hide timestamp and body fields in logs explorer (raw, defa…
Browse files Browse the repository at this point in the history
…ult, column views) (#6903)

* feat: show/hide timestamp and body fields in logs explorer (raw, default, column views)

* fix: add width to log indicator column to ensure that a single column doesn't take half the space

* fix: handle edge cases and fix issues for show/hide body and timestamp in logs explorer
  • Loading branch information
ahmadshaheer authored Jan 27, 2025
1 parent 61a6c21 commit 98cdbcd
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 119 deletions.
50 changes: 28 additions & 22 deletions frontend/src/components/Logs/ListLogView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,36 +220,42 @@ function ListLogView({
<LogStateIndicator type={logType} fontSize={fontSize} />
<div>
<LogContainer fontSize={fontSize}>
<LogGeneralField
fieldKey="Log"
fieldValue={flattenLogData.body}
linesPerRow={linesPerRow}
fontSize={fontSize}
/>
{updatedSelecedFields.some((field) => field.name === 'body') && (
<LogGeneralField
fieldKey="Log"
fieldValue={flattenLogData.body}
linesPerRow={linesPerRow}
fontSize={fontSize}
/>
)}
{flattenLogData.stream && (
<LogGeneralField
fieldKey="Stream"
fieldValue={flattenLogData.stream}
fontSize={fontSize}
/>
)}
<LogGeneralField
fieldKey="Timestamp"
fieldValue={timestampValue}
fontSize={fontSize}
/>

{updatedSelecedFields.map((field) =>
isValidLogField(flattenLogData[field.name] as never) ? (
<LogSelectedField
key={field.name}
fieldKey={field.name}
fieldValue={flattenLogData[field.name] as never}
onAddToQuery={onAddToQuery}
fontSize={fontSize}
/>
) : null,
{updatedSelecedFields.some((field) => field.name === 'timestamp') && (
<LogGeneralField
fieldKey="Timestamp"
fieldValue={timestampValue}
fontSize={fontSize}
/>
)}

{updatedSelecedFields
.filter((field) => !['timestamp', 'body'].includes(field.name))
.map((field) =>
isValidLogField(flattenLogData[field.name] as never) ? (
<LogSelectedField
key={field.name}
fieldKey={field.name}
fieldValue={flattenLogData[field.name] as never}
onAddToQuery={onAddToQuery}
fontSize={fontSize}
/>
) : null,
)}
</LogContainer>
</div>
</div>
Expand Down
45 changes: 32 additions & 13 deletions frontend/src/components/Logs/RawLogView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ function RawLogView({
);

const attributesValues = updatedSelecedFields
.filter((field) => !['timestamp', 'body'].includes(field.name))
.map((field) => flattenLogData[field.name])
.filter((attribute) => {
// loadash isEmpty doesnot work with numbers
Expand All @@ -93,22 +94,40 @@ function RawLogView({
const { formatTimezoneAdjustedTimestamp } = useTimezone();

const text = useMemo(() => {
const date =
typeof data.timestamp === 'string'
? formatTimezoneAdjustedTimestamp(
data.timestamp,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
data.timestamp / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);

return `${date} | ${attributesText} ${data.body}`;
const parts = [];

// Check if timestamp is selected
const showTimestamp = selectedFields.some(
(field) => field.name === 'timestamp',
);
if (showTimestamp) {
const date =
typeof data.timestamp === 'string'
? formatTimezoneAdjustedTimestamp(
data.timestamp,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
data.timestamp / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
parts.push(date);
}

// Check if body is selected
const showBody = selectedFields.some((field) => field.name === 'body');
if (showBody) {
parts.push(`${attributesText} ${data.body}`);
} else {
parts.push(attributesText);
}

return parts.join(' | ');
}, [
selectedFields,
attributesText,
data.timestamp,
data.body,
attributesText,
formatTimezoneAdjustedTimestamp,
]);

Expand Down
114 changes: 63 additions & 51 deletions frontend/src/components/Logs/TableView/useTableView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {

const columns: ColumnsType<Record<string, unknown>> = useMemo(() => {
const fieldColumns: ColumnsType<Record<string, unknown>> = fields
.filter((e) => e.name !== 'id')
.filter((e) => !['id', 'body', 'timestamp'].includes(e.name))
.map(({ name }) => ({
title: name,
dataIndex: name,
Expand Down Expand Up @@ -92,58 +92,70 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
),
}),
},
{
title: 'timestamp',
dataIndex: 'timestamp',
key: 'timestamp',
// https://github.com/ant-design/ant-design/discussions/36886
render: (field): ColumnTypeRender<Record<string, unknown>> => {
const date =
typeof field === 'string'
? formatTimezoneAdjustedTimestamp(
field,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
field / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
return {
children: (
<div className="table-timestamp">
<Typography.Paragraph ellipsis className={cx('text', fontSize)}>
{date}
</Typography.Paragraph>
</div>
),
};
},
},
...(fields.some((field) => field.name === 'timestamp')
? [
{
title: 'timestamp',
dataIndex: 'timestamp',
key: 'timestamp',
// https://github.com/ant-design/ant-design/discussions/36886
render: (
field: string | number,
): ColumnTypeRender<Record<string, unknown>> => {
const date =
typeof field === 'string'
? formatTimezoneAdjustedTimestamp(
field,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
field / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
return {
children: (
<div className="table-timestamp">
<Typography.Paragraph ellipsis className={cx('text', fontSize)}>
{date}
</Typography.Paragraph>
</div>
),
};
},
},
]
: []),
...(appendTo === 'center' ? fieldColumns : []),
{
title: 'body',
dataIndex: 'body',
key: 'body',
render: (field): ColumnTypeRender<Record<string, unknown>> => ({
props: {
style: defaultTableStyle,
},
children: (
<TableBodyContent
dangerouslySetInnerHTML={{
__html: convert.toHtml(
dompurify.sanitize(unescapeString(field), {
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
}),
...(fields.some((field) => field.name === 'body')
? [
{
title: 'body',
dataIndex: 'body',
key: 'body',
render: (
field: string | number,
): ColumnTypeRender<Record<string, unknown>> => ({
props: {
style: defaultTableStyle,
},
children: (
<TableBodyContent
dangerouslySetInnerHTML={{
__html: convert.toHtml(
dompurify.sanitize(unescapeString(field as string), {
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
}),
),
}}
fontSize={fontSize}
linesPerRow={linesPerRow}
isDarkMode={isDarkMode}
/>
),
}}
fontSize={fontSize}
linesPerRow={linesPerRow}
isDarkMode={isDarkMode}
/>
),
}),
},
}),
},
]
: []),
...(appendTo === 'end' ? fieldColumns : []),
];
}, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,11 +417,13 @@ export default function LogsFormatOptionsMenu({
{key}
</Tooltip>
</div>
<X
className="delete-btn"
size={14}
onClick={(): void => addColumn.onRemove(id as string)}
/>
{addColumn?.value?.length > 1 && (
<X
className="delete-btn"
size={14}
onClick={(): void => addColumn.onRemove(id as string)}
/>
)}
</div>
))}
{addColumn && addColumn?.value?.length === 0 && (
Expand Down
21 changes: 16 additions & 5 deletions frontend/src/container/ExplorerOptions/ExplorerOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import useErrorNotification from 'hooks/useErrorNotification';
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
import { useNotifications } from 'hooks/useNotifications';
import { mapCompositeQueryFromQuery } from 'lib/newQueryBuilder/queryBuilderMappers/mapCompositeQueryFromQuery';
import { cloneDeep, isEqual } from 'lodash-es';
import { cloneDeep, isEqual, omit } from 'lodash-es';
import {
Check,
ConciergeBell,
Expand Down Expand Up @@ -256,13 +256,17 @@ function ExplorerOptions({
const { handleExplorerTabChange } = useHandleExplorerTabChange();

const { options, handleOptionsChange } = useOptionsMenu({
storageKey: LOCALSTORAGE.TRACES_LIST_OPTIONS,
dataSource: DataSource.TRACES,
storageKey:
sourcepage === DataSource.TRACES
? LOCALSTORAGE.TRACES_LIST_OPTIONS
: LOCALSTORAGE.LOGS_LIST_OPTIONS,
dataSource: sourcepage,
aggregateOperator: StringOperators.NOOP,
});

type ExtraData = {
selectColumns?: BaseAutocompleteData[];
version?: number;
};

const updateOrRestoreSelectColumns = (
Expand All @@ -283,14 +287,20 @@ function ExplorerOptions({
console.error('Error parsing extraData:', error);
}

let backwardCompatibleOptions = options;

if (!extraData?.version) {
backwardCompatibleOptions = omit(options, 'version');
}

if (extraData.selectColumns?.length) {
handleOptionsChange({
...options,
...backwardCompatibleOptions,
selectColumns: extraData.selectColumns,
});
} else if (!isEqual(defaultTraceSelectedColumns, options.selectColumns)) {
handleOptionsChange({
...options,
...backwardCompatibleOptions,
selectColumns: defaultTraceSelectedColumns,
});
}
Expand Down Expand Up @@ -423,6 +433,7 @@ function ExplorerOptions({
extraData: JSON.stringify({
color,
selectColumns: options.selectColumns,
version: 1,
}),
notifications,
panelType: panelType || PANEL_TYPES.LIST,
Expand Down
36 changes: 19 additions & 17 deletions frontend/src/container/LogsExplorerList/InfinityTableView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,23 +121,25 @@ const InfinityTable = forwardRef<TableVirtuosoHandle, InfinityTableProps>(
const tableHeader = useCallback(
() => (
<tr>
{tableColumns.map((column) => {
const isDragColumn = column.key !== 'expand';

return (
<TableHeaderCellStyled
$isLogIndicator={column.key === 'state-indicator'}
$isDarkMode={isDarkMode}
$isDragColumn={isDragColumn}
key={column.key}
fontSize={tableViewProps?.fontSize}
// eslint-disable-next-line react/jsx-props-no-spreading
{...(isDragColumn && { className: 'dragHandler' })}
>
{(column.title as string).replace(/^\w/, (c) => c.toUpperCase())}
</TableHeaderCellStyled>
);
})}
{tableColumns
.filter((column) => column.key)
.map((column) => {
const isDragColumn = column.key !== 'expand';

return (
<TableHeaderCellStyled
$isLogIndicator={column.key === 'state-indicator'}
$isDarkMode={isDarkMode}
$isDragColumn={isDragColumn}
key={column.key}
fontSize={tableViewProps?.fontSize}
// eslint-disable-next-line react/jsx-props-no-spreading
{...(isDragColumn && { className: 'dragHandler' })}
>
{(column.title as string).replace(/^\w/, (c) => c.toUpperCase())}
</TableHeaderCellStyled>
);
})}
</tr>
),
[tableColumns, isDarkMode, tableViewProps?.fontSize],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const TableCellStyled = styled.td<TableHeaderCellStyledProps>`
props.$isDarkMode ? 'inherit' : themeColors.whiteCream};
${({ $isLogIndicator }): string =>
$isLogIndicator ? 'padding: 0 0 0 8px;' : ''}
$isLogIndicator ? 'padding: 0 0 0 8px;width: 15px;' : ''}
color: ${(props): string =>
props.$isDarkMode ? themeColors.white : themeColors.bckgGrey};
`;
Expand Down
Loading

0 comments on commit 98cdbcd

Please sign in to comment.