mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
Log Side Panel: exceptions ui improvements (#118)
This commit is contained in:
parent
9c2e279012
commit
abe3b12515
3 changed files with 82 additions and 11 deletions
5
.changeset/young-pans-search.md
Normal file
5
.changeset/young-pans-search.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hyperdx/app': patch
|
||||
---
|
||||
|
||||
Log Side Panel: exceptions ui improvements
|
||||
|
|
@ -492,6 +492,7 @@ function isExceptionSpan({ logData }: { logData: any }) {
|
|||
|
||||
function TraceSubpanel({
|
||||
logData,
|
||||
isException,
|
||||
onClose,
|
||||
onPropertyAddClick,
|
||||
generateChartUrl,
|
||||
|
|
@ -500,6 +501,7 @@ function TraceSubpanel({
|
|||
toggleColumn,
|
||||
}: {
|
||||
logData: any;
|
||||
isException: boolean;
|
||||
onClose: () => void;
|
||||
generateSearchUrl: (query?: string, timeRange?: [Date, Date]) => string;
|
||||
generateChartUrl: (config: {
|
||||
|
|
@ -558,7 +560,6 @@ function TraceSubpanel({
|
|||
}, [_searchedQuery, _inputQuery]);
|
||||
// Allows us to determine if the user has changed the search query
|
||||
const searchedQuery = _searchedQuery ?? '';
|
||||
const isException = isExceptionSpan({ logData: selectedLogData });
|
||||
|
||||
const exceptionBreadcrumbs = useMemo<StacktraceBreadcrumb[]>(() => {
|
||||
try {
|
||||
|
|
@ -1875,6 +1876,11 @@ const ExceptionSubpanel = ({
|
|||
[firstException.stacktrace?.frames],
|
||||
);
|
||||
|
||||
const chronologicalBreadcrumbs = useMemo(
|
||||
() => breadcrumbs?.slice().reverse() ?? [],
|
||||
[breadcrumbs],
|
||||
);
|
||||
|
||||
// TODO: show all frames (stackable)
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -1936,7 +1942,7 @@ const ExceptionSubpanel = ({
|
|||
<SectionWrapper>
|
||||
<Table
|
||||
columns={breadcrumbColumns}
|
||||
data={breadcrumbs}
|
||||
data={chronologicalBreadcrumbs}
|
||||
emptyMessage="No breadcrumbs found"
|
||||
/>
|
||||
</SectionWrapper>
|
||||
|
|
@ -2011,7 +2017,11 @@ export default function LogSidePanel({
|
|||
}, [setQueryTab, isNestedPanel, onClose]);
|
||||
|
||||
const logData = useMemo(() => logDataRaw?.data[0], [logDataRaw]);
|
||||
const displayedTab = tab ?? (logData?.type === 'span' ? 'trace' : 'parsed');
|
||||
|
||||
const isException = useMemo(() => isExceptionSpan({ logData }), [logData]);
|
||||
|
||||
const displayedTab =
|
||||
tab ?? (logData?.type === 'span' || isException ? 'trace' : 'parsed');
|
||||
|
||||
// Keep track of sub-drawers so we can disable closing this root drawer
|
||||
const [subDrawerOpen, setSubDrawerOpen] = useState(false);
|
||||
|
|
@ -2177,6 +2187,7 @@ export default function LogSidePanel({
|
|||
>
|
||||
<TraceSubpanel
|
||||
logData={logData}
|
||||
isException={isException}
|
||||
onPropertyAddClick={onPropertyAddClick}
|
||||
generateSearchUrl={generateSearchUrl}
|
||||
generateChartUrl={generateChartUrl}
|
||||
|
|
|
|||
|
|
@ -158,27 +158,82 @@ export const stacktraceColumns: ColumnDef<StacktraceFrame>[] = [
|
|||
},
|
||||
];
|
||||
|
||||
const MAX_URL_LENGTH = 120;
|
||||
const Url = ({ url }: { url?: string }) => (
|
||||
<span className="text-slate-300" title={url}>
|
||||
{url == null
|
||||
? ''
|
||||
: url.length > MAX_URL_LENGTH
|
||||
? `${url.slice(0, MAX_URL_LENGTH)}...`
|
||||
: url}
|
||||
</span>
|
||||
);
|
||||
|
||||
export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
|
||||
{
|
||||
accessorKey: 'category',
|
||||
header: 'Category',
|
||||
size: 180,
|
||||
cell: ({ row }) => (
|
||||
<span className="text-slate-300">{row.original.category}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'message',
|
||||
header: 'Message',
|
||||
header: 'Data',
|
||||
size: UNDEFINED_WIDTH,
|
||||
cell: ({ row }) =>
|
||||
row.original.message || <span className="text-slate-500">Empty</span>,
|
||||
cell: ({ row }) => {
|
||||
// fetch
|
||||
if (row.original.category === 'fetch' && row.original.data) {
|
||||
const { method, url } = row.original.data;
|
||||
return (
|
||||
<>
|
||||
<span>{method} </span>
|
||||
<span className="text-slate-300" title={url}>
|
||||
<Url url={url} />
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// navigation
|
||||
if (row.original.category === 'navigation' && row.original.data) {
|
||||
const { from, to } = row.original.data;
|
||||
return (
|
||||
<>
|
||||
<span className="text-slate-300" title={from}>
|
||||
<Url url={from} />
|
||||
</span>
|
||||
<span>{' → '}</span>
|
||||
<span className="text-slate-300" title={to}>
|
||||
<Url url={to} />
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
row.original.message || <span className="text-slate-500">Empty</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'level',
|
||||
header: '',
|
||||
size: 140,
|
||||
cell: ({ row }) =>
|
||||
row.original.level ? <LogLevel level={row.original.level} /> : null,
|
||||
size: 80,
|
||||
cell: ({ row }) => {
|
||||
if (row.original.category === 'fetch' && row.original.data) {
|
||||
const { status_code } = row.original.data;
|
||||
return parseInt(status_code) >= 400 ? (
|
||||
<span className="text-danger"> {status_code}</span>
|
||||
) : (
|
||||
<span className="text-slate-500"> {status_code}</span>
|
||||
);
|
||||
}
|
||||
return row.original.level ? (
|
||||
<LogLevel level={row.original.level} />
|
||||
) : null;
|
||||
},
|
||||
},
|
||||
{
|
||||
header: 'Timestamp',
|
||||
|
|
@ -200,9 +255,9 @@ export const headerColumns: ColumnDef<[string, string]>[] = [
|
|||
header: 'Header',
|
||||
size: 260,
|
||||
cell: ({ row }) => (
|
||||
<span className="text-slate-300 text-truncate" title={row.original[0]}>
|
||||
<div className="text-slate-300 text-truncate" title={row.original[0]}>
|
||||
{row.original[0]}
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue