Skip to content

Commit

Permalink
✨ better event description
Browse files Browse the repository at this point in the history
  • Loading branch information
BenoitZugmeyer committed Aug 8, 2023
1 parent 773693d commit cd350a9
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 34 deletions.
162 changes: 128 additions & 34 deletions developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { Badge } from '@mantine/core'
import { Badge, Box } from '@mantine/core'
import type { ReactNode } from 'react'
import React, { useRef, useState } from 'react'
import type { TelemetryEvent } from '../../../../../../packages/core/src/domain/telemetry'
import type { LogsEvent } from '../../../../../../packages/logs/src/logsEvent.types'
import type {
RumActionEvent,
RumErrorEvent,
RumLongTaskEvent,
RumResourceEvent,
RumViewEvent,
} from '../../../../../../packages/rum-core/src/rumEvent.types'
import type { SdkEvent } from '../../../sdkEvent'
import { isTelemetryEvent, isRumEvent } from '../../../sdkEvent'
import { safeTruncate } from '../../../../../../packages/core/src/tools/utils/stringUtils'
import { isTelemetryEvent, isLogEvent, isRumEvent } from '../../../sdkEvent'
import { formatDuration } from '../../../formatNumber'
import { Json } from '../../json'
import { LazyCollapse } from '../../lazyCollapse'

Expand All @@ -22,6 +32,19 @@ const LOG_STATUS_COLOR = {
debug: 'cyan',
}

const RESOURCE_TYPE_LABELS: Record<string, string | undefined> = {
xhr: 'XHR',
fetch: 'Fetch',
document: 'Document',
beacon: 'Beacon',
css: 'CSS',
js: 'JS',
image: 'Image',
font: 'Font',
media: 'Media',
other: 'Other',
}

export function EventRow({ event }: { event: SdkEvent }) {
const [isCollapsed, setIsCollapsed] = useState(true)
const collapseRef = useRef<HTMLDivElement>(null)
Expand Down Expand Up @@ -49,7 +72,7 @@ export function EventRow({ event }: { event: SdkEvent }) {
)}
</td>
<td>
{getRumEventDescription(event)}{' '}
<EventDescription event={event} />
<LazyCollapse in={!isCollapsed} ref={collapseRef}>
<Json value={event} defaultCollapseLevel={0} />
</LazyCollapse>
Expand All @@ -58,46 +81,117 @@ export function EventRow({ event }: { event: SdkEvent }) {
)
}

function getRumEventDescription(event: SdkEvent): string | undefined {
export const EventDescription = React.memo(({ event }: { event: SdkEvent }) => {
if (isRumEvent(event)) {
switch (event.type) {
case 'view':
return `${event.view.loading_type || ''} ${getViewPage(event.view)}`
case 'action':
return `${event.action.type} action ${event.action.target?.name || ''} on page ${getViewPage(event.view)} `
case 'resource':
return `${event.resource.type} ${event.resource.url}`
case 'error':
return `${event.error.source} error ${event.error.message}`
return <ViewDescription event={event} />
case 'long_task':
return `long task of ${(event.long_task.duration / 1000).toLocaleString()} ms`
}
} else if (isTelemetryEvent(event)) {
switch (event.telemetry.type) {
case 'log':
return event.telemetry.message
case 'configuration':
return jsonOverview(event.telemetry.configuration)
default:
return ''
return <LongTaskDescription event={event} />
case 'error':
return <ErrorDescription event={event} />
case 'resource':
return <ResourceDescription event={event} />
case 'action':
return <ActionDescription event={event} />
}
} else if (isLogEvent(event)) {
return <LogDescription event={event} />
} else {
return event.message
return <TelemetryDescription event={event} />
}
})

function LogDescription({ event }: { event: LogsEvent }) {
return <>{event.message}</>
}

function getViewPage(view: { name?: string; url: string }) {
return `${view.name || new URL(view.url).pathname}`
function TelemetryDescription({ event }: { event: TelemetryEvent }) {
if (event.telemetry.type === 'configuration') {
return <Emphasis>Configuration</Emphasis>
}
return <>{event.telemetry.message}</>
}

function jsonOverview(jsonObject: object) {
const replacer = (key: any, value: any): any => {
if (key && typeof value === 'object') {
return '{...}'
}
return value
function ViewDescription({ event }: { event: RumViewEvent }) {
const isRouteChange = event.view.loading_type === 'route_change'

return (
<>
{isRouteChange ? 'SPA Route Change' : 'Load Page'} <Emphasis>{getViewName(event.view)}</Emphasis>
</>
)
}

function ActionDescription({ event }: { event: RumActionEvent }) {
const actionName = event.action.target?.name
const frustrationTypes = event.action.frustration?.type

if (event.action.type === 'custom') {
return (
<>
Custom user action <Emphasis>{event.action.target?.name}</Emphasis>
</>
)
}
const overview = JSON.stringify(jsonObject, replacer)
const unquoted = overview.replace(/"([^"]+)":/g, '$1:')
return safeTruncate(unquoted, 100, '...')

return (
<>
{frustrationTypes && frustrationTypes.length > 0 && '😡 '}
<Emphasis>{event.action.type}</Emphasis>
{actionName && (
<>
{' '}
on <Emphasis>{actionName}</Emphasis>
</>
)}
</>
)
}
function LongTaskDescription({ event }: { event: RumLongTaskEvent }) {
return (
<>
Long task of <Emphasis>{formatDuration(event.long_task.duration)}</Emphasis>
</>
)
}

function ErrorDescription({ event }: { event: RumErrorEvent }) {
return (
<>
<Emphasis>{event.error.source}</Emphasis> error {event.error.type}: {event.error.message}
</>
)
}

function ResourceDescription({ event }: { event: RumResourceEvent }) {
const resourceType = event.resource.type
const isAsset = resourceType !== 'xhr' && resourceType !== 'fetch'

if (isAsset) {
return (
<>
Load <Emphasis>{RESOURCE_TYPE_LABELS[resourceType] || RESOURCE_TYPE_LABELS.other}</Emphasis> file{' '}
<Emphasis>{event.resource.url}</Emphasis>
</>
)
}

return (
<>
{RESOURCE_TYPE_LABELS[resourceType]} request <Emphasis>{event.resource.url}</Emphasis>
</>
)
}

function Emphasis({ children }: { children: ReactNode }) {
return (
<Box component="span" sx={{ fontWeight: 'bold' }}>
{children}
</Box>
)
}

function getViewName(view: { name?: string; url: string }) {
return `${view.name || new URL(view.url).pathname}`
}
4 changes: 4 additions & 0 deletions developer-extension/src/panel/formatNumber.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export function formatNumber(n: number): string {
return new Intl.NumberFormat('en-US', {}).format(n)
}

export function formatDuration(ns: number): string {
return new Intl.NumberFormat('en-US', { style: 'unit', unit: 'millisecond' }).format(ns / 1_000_000)
}

0 comments on commit cd350a9

Please sign in to comment.