Skip to content

Commit

Permalink
feat(overlay): Enhanced Trace detail page. (#557)
Browse files Browse the repository at this point in the history
Related #551 and #544.
  • Loading branch information
Shubhdeep12 authored Nov 8, 2024
1 parent 4be6666 commit aba5c07
Show file tree
Hide file tree
Showing 18 changed files with 194 additions and 291 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-poems-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@spotlightjs/overlay': minor
---

- Added subtabs in trace detail page
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
</p>

# What's Spotlight? [![npm version](https://img.shields.io/npm/v/@spotlightjs/spotlight.svg)](https://www.npmjs.com/package/@spotlightjs/spotlight)

Spotlight is Sentry for Development. Inspired by an old project, Django Debug Toolbar, Spotlight brings a rich debug
overlay into development environments, and it does it by leveraging the existing power of Sentry's SDKs.


## Links

- [![Documentation](https://img.shields.io/badge/documentation-spotlight-indigo.svg)](https://spotlightjs.com/about/)
Expand All @@ -22,4 +22,3 @@ overlay into development environments, and it does it by leveraging the existing
- [Setup Spotlight](https://spotlightjs.com/setup/)
- [Sidecar](https://spotlightjs.com/sidecar/)
- [Integrations](https://spotlightjs.com/integrations/)

Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default function EventDetails() {
</div>
<div>
S:{' '}
<Link className="cursor-pointer underline" to={`/traces/${traceCtx.trace_id}/${traceCtx.span_id}`}>
<Link className="cursor-pointer underline" to={`/traces/${traceCtx.trace_id}/spans/${traceCtx.span_id}`}>
{traceCtx.span_id}
</Link>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ function renderEvent(event: SentryEvent) {
return <EventSummary event={event} />;
}

export default function EventList() {
const events = useSentryEvents();
export default function EventList({ traceId }: { traceId?: string }) {
const events = useSentryEvents(traceId);
const helpers = useSentryHelpers();
const context = useSpotlightContext();

Expand Down Expand Up @@ -46,7 +46,7 @@ export default function EventList() {
<Link
className="hover:bg-primary-900 flex cursor-pointer items-center gap-x-4 px-6 py-2"
key={e.event_id}
to={`${e.event_id}/details`}
to={`/errors/${e.event_id}/details`}
>
<PlatformIcon event={e} className="text-primary-300 rounded-md" />
<div className="text-primary-300 flex w-48 flex-col truncate font-mono text-sm">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ const QuerySummary = ({ showAll }: { showAll: boolean }) => {
</Link>
</td>
<td className="text-primary-200 w-[15%] whitespace-nowrap px-6 py-4 text-right text-sm font-medium">
<Link className="truncate hover:underline" to={`/traces/${span.trace_id}/${span.span_id}`}>
<Link className="truncate hover:underline" to={`/traces/${span.trace_id}/spans/${span.span_id}`}>
{span.span_id}
</Link>
</td>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import sentryDataCache from '~/integrations/sentry/data/sentryDataCache';
import type { Tags as TagsType, Trace } from '~/integrations/sentry/types';
import { getDuration } from '~/integrations/sentry/utils/duration';
import DateTime from '../../../DateTime';
import Tags from '../../../Tags';

type TraceGeneralInfoProps = {
trace: Trace;
};

function TraceGeneralInfo({ trace }: TraceGeneralInfoProps) {
const traceId = trace.trace_id;
return (
<div>
<h2 className="mb-2 font-bold uppercase">General</h2>
<table className="w-full text-sm">
<tbody>
{[
['Trace Id', traceId || '-'],
['Spans', trace.spans.length || '-'],
['Transactions', trace.transactions.length || '-'],
['Errors', trace.errors || '-'],
[
'Start Timestamp',
trace.start_timestamp ? <DateTime key="Start Timestamp" date={trace.start_timestamp} /> : '-',
],
['Total Duration', `${getDuration(trace.start_timestamp, trace.timestamp).toLocaleString()} ms`],
].map(([key, value]) => (
<tr key={key as string} className="text-primary-300">
<th className=" w-1/12 py-0.5 pr-4 text-left font-mono font-normal">
<div className="w-full truncate">{key}</div>
</th>
<td className="py-0.5">
<pre className="whitespace-nowrap font-mono">{value}</pre>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}

type TraceTagsProps = {
trace: Trace;
};

function TraceTags({ trace }: TraceTagsProps) {
const tags: TagsType = trace.transactions
.map(tsx => tsx.tags || {})
.reduce((prev, current) => Object.assign(prev, current), {} as TagsType);

return (
Object.keys(tags).length > 0 && (
<div>
<h2 className="mb-2 font-bold uppercase">Tags</h2>
<Tags tags={tags} />
</div>
)
);
}

type TraceContextProps = {
traceId: string;
};

export default function TraceContext({ traceId }: TraceContextProps) {
const trace = sentryDataCache.getTraceById(traceId);

return (
<div className="space-y-4 px-6 py-4">
<TraceGeneralInfo trace={trace} />
<TraceTags trace={trace} />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Trace } from '../../../../types';
import TraceIcon from '../../TraceIcon';

type TraceDetailHeaderProps = {
trace: Trace;
};

export default function TraceDetailHeader({ trace }: TraceDetailHeaderProps) {
return (
<div className="border-b-primary-700 bg-primary-950 flex items-center gap-x-2 border-b px-6 py-4">
<TraceIcon trace={trace} />
<h1 className="max-w-full flex-1 truncate text-2xl">{trace.rootTransactionName}</h1>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,27 @@
import { useState } from 'react';
import { Link, useLocation, useParams } from 'react-router-dom';
import dataCache from '../../../data/sentryDataCache';
import { getDuration } from '../../../utils/duration';
import DateTime from '../../DateTime';
import SpanDetails from '../spans/SpanDetails';
import SpanTree from '../spans/SpanTree';
import TraceInfo from '../traceInfo';
import TraceDetailHeader from './TraceDetailHeader';
import { useParams } from 'react-router-dom';
import sentryDataCache from '../../../../data/sentryDataCache';
import { getDuration } from '../../../../utils/duration';
import DateTime from '../../../DateTime';
import SpanDetails from '../../spans/SpanDetails';
import SpanTree from '../../spans/SpanTree';

export default function TraceDetails() {
const { traceId, spanId } = useParams();
const { pathname } = useLocation();
type TraceTreeViewProps = { traceId: string };

const [spanNodeWidth, setSpanNodeWidth] = useState<number>(50);
export const DEFAULT_SPAN_NODE_WIDTH = 50;

if (!traceId) {
return <p className="text-primary-300 p-6">Unknown trace id</p>;
}
export default function TraceTreeview({ traceId }: TraceTreeViewProps) {
const { spanId } = useParams();

const trace = dataCache.getTraceById(traceId);
const [spanNodeWidth, setSpanNodeWidth] = useState<number>(DEFAULT_SPAN_NODE_WIDTH);

if (!trace) {
return (
<p className="text-primary-300 p-6">
Trace not found. Check for more{' '}
<Link to="/traces" className="underline">
traces
</Link>
</p>
);
}
const span = spanId ? dataCache.getSpanById(trace.trace_id, spanId) : undefined;
const isTraceInfo = pathname === `/traces/${traceId}/info`;
const trace = sentryDataCache.getTraceById(traceId);
const span = spanId ? sentryDataCache.getSpanById(traceId, spanId) : undefined;
const startTimestamp = trace.start_timestamp;
const totalDuration = trace.timestamp - startTimestamp;

return (
<>
<TraceDetailHeader trace={trace} />
<div className="px-6 py-4">
<div className="text-primary-300 flex flex-1 items-center gap-x-1">
<div className="text-primary-200">
Expand Down Expand Up @@ -73,8 +57,6 @@ export default function TraceDetails() {
totalTransactions={(trace.transactions || []).length}
/>
) : null}

{isTraceInfo && <TraceInfo traceContext={trace} />}
</>
);
}
Loading

0 comments on commit aba5c07

Please sign in to comment.