react-native-nitro-tracing 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/NitroTracing.podspec +32 -0
- package/README.md +75 -0
- package/android/CMakeLists.txt +49 -0
- package/android/build.gradle +133 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/proguard-rules.pro +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +47 -0
- package/android/src/main/java/com/margelo/nitro/nitrotracing/HermesSamplingGuard.kt +43 -0
- package/android/src/main/java/com/margelo/nitro/nitrotracing/NitroTracingFrameSource.kt +36 -0
- package/android/src/main/java/com/margelo/nitro/nitrotracing/NitroTracingPackage.kt +31 -0
- package/client.ts +15 -0
- package/cpp/HermesSampling.cpp +26 -0
- package/cpp/HermesSampling.hpp +10 -0
- package/cpp/HybridRecording.cpp +66 -0
- package/cpp/HybridRecording.hpp +30 -0
- package/cpp/HybridTraceSpan.cpp +10 -0
- package/cpp/HybridTraceSpan.hpp +17 -0
- package/cpp/HybridTracing.cpp +10 -0
- package/cpp/HybridTracing.hpp +10 -0
- package/cpp/NativeConversions.cpp +77 -0
- package/cpp/NativeConversions.hpp +15 -0
- package/cpp/core/NativeSampler.cpp +152 -0
- package/cpp/core/NativeSampler.hpp +56 -0
- package/cpp/core/Recorder.cpp +218 -0
- package/cpp/core/Recorder.hpp +60 -0
- package/cpp/core/Retention.cpp +26 -0
- package/cpp/core/Retention.hpp +7 -0
- package/cpp/core/TraceJson.cpp +214 -0
- package/cpp/core/TraceJson.hpp +7 -0
- package/cpp/core/TraceTypes.hpp +62 -0
- package/expo.ts +2 -0
- package/ios/NitroTracingFrameSource.mm +35 -0
- package/lib/commonjs/client.cjs +767 -0
- package/lib/commonjs/client.cjs.map +7 -0
- package/lib/commonjs/expo.cjs +88 -0
- package/lib/commonjs/expo.cjs.map +7 -0
- package/lib/commonjs/index.cjs +28 -0
- package/lib/commonjs/index.cjs.map +7 -0
- package/lib/commonjs/performance.cjs +112 -0
- package/lib/commonjs/performance.cjs.map +7 -0
- package/lib/commonjs/plugins.cjs +477 -0
- package/lib/commonjs/plugins.cjs.map +7 -0
- package/lib/commonjs/react.cjs +3833 -0
- package/lib/commonjs/react.cjs.map +7 -0
- package/lib/commonjs/release-profiler.cjs +142 -0
- package/lib/commonjs/release-profiler.cjs.map +7 -0
- package/lib/commonjs/sentry.cjs +188 -0
- package/lib/commonjs/sentry.cjs.map +7 -0
- package/lib/module/client.mjs +768 -0
- package/lib/module/client.mjs.map +7 -0
- package/lib/module/expo.mjs +62 -0
- package/lib/module/expo.mjs.map +7 -0
- package/lib/module/index.mjs +7 -0
- package/lib/module/index.mjs.map +7 -0
- package/lib/module/performance.mjs +89 -0
- package/lib/module/performance.mjs.map +7 -0
- package/lib/module/plugins.mjs +461 -0
- package/lib/module/plugins.mjs.map +7 -0
- package/lib/module/react.mjs +3851 -0
- package/lib/module/react.mjs.map +7 -0
- package/lib/module/release-profiler.mjs +137 -0
- package/lib/module/release-profiler.mjs.map +7 -0
- package/lib/module/sentry.mjs +165 -0
- package/lib/module/sentry.mjs.map +7 -0
- package/lib/typescript/client.d.ts +4 -0
- package/lib/typescript/expo.d.ts +2 -0
- package/lib/typescript/performance.d.ts +2 -0
- package/lib/typescript/plugins.d.ts +12 -0
- package/lib/typescript/react.d.ts +5 -0
- package/lib/typescript/release-profiler.d.ts +2 -0
- package/lib/typescript/sentry.d.ts +2 -0
- package/lib/typescript/src/client/TracingSink.d.ts +10 -0
- package/lib/typescript/src/client/createTraceClient.d.ts +82 -0
- package/lib/typescript/src/client/playground.d.ts +12 -0
- package/lib/typescript/src/expo/ExpoAdapter.d.ts +15 -0
- package/lib/typescript/src/expo/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts +6 -0
- package/lib/typescript/src/plugins/TracePlugin.d.ts +22 -0
- package/lib/typescript/src/plugins/errors.d.ts +15 -0
- package/lib/typescript/src/plugins/nativeMetrics.d.ts +13 -0
- package/lib/typescript/src/plugins/navigation.d.ts +29 -0
- package/lib/typescript/src/plugins/network.d.ts +23 -0
- package/lib/typescript/src/plugins/orderSpans.d.ts +3 -0
- package/lib/typescript/src/plugins/performance.d.ts +13 -0
- package/lib/typescript/src/plugins/releaseProfiler.d.ts +25 -0
- package/lib/typescript/src/plugins/runtimeMetrics.d.ts +17 -0
- package/lib/typescript/src/plugins/sentry.d.ts +15 -0
- package/lib/typescript/src/plugins/startPlugins.d.ts +4 -0
- package/lib/typescript/src/react/DetailView.d.ts +11 -0
- package/lib/typescript/src/react/ExplorerFilters.d.ts +9 -0
- package/lib/typescript/src/react/ExplorerView.d.ts +9 -0
- package/lib/typescript/src/react/InspectorControls.d.ts +229 -0
- package/lib/typescript/src/react/InspectorHeader.d.ts +8 -0
- package/lib/typescript/src/react/InspectorSheet.d.ts +16 -0
- package/lib/typescript/src/react/MetricsView.d.ts +7 -0
- package/lib/typescript/src/react/SummaryView.d.ts +11 -0
- package/lib/typescript/src/react/TimelineView.d.ts +8 -0
- package/lib/typescript/src/react/TraceInspector.d.ts +11 -0
- package/lib/typescript/src/react/TraceOverlay.d.ts +17 -0
- package/lib/typescript/src/react/explorerModel.d.ts +38 -0
- package/lib/typescript/src/react/labels.d.ts +203 -0
- package/lib/typescript/src/react/native.d.ts +42 -0
- package/lib/typescript/src/react/readSnapshot.d.ts +4 -0
- package/lib/typescript/src/react/store.d.ts +9 -0
- package/lib/typescript/src/react/topics.d.ts +80 -0
- package/lib/typescript/src/react/useAppReadyMetric.d.ts +3 -0
- package/lib/typescript/src/react/useLiveRecording.d.ts +4 -0
- package/lib/typescript/src/react/useTraceViewer.d.ts +140 -0
- package/lib/typescript/src/react/viewerModel.d.ts +59 -0
- package/lib/typescript/src/specs/Recording.nitro.d.ts +31 -0
- package/lib/typescript/src/specs/TraceSpan.nitro.d.ts +14 -0
- package/lib/typescript/src/specs/Tracing.nitro.d.ts +17 -0
- package/lib/typescript/src/types/CompletedSpanOptions.d.ts +15 -0
- package/lib/typescript/src/types/EventContext.d.ts +8 -0
- package/lib/typescript/src/types/MarkEvent.d.ts +4 -0
- package/lib/typescript/src/types/MarkOptions.d.ts +6 -0
- package/lib/typescript/src/types/MetricEvent.d.ts +8 -0
- package/lib/typescript/src/types/MetricOptions.d.ts +10 -0
- package/lib/typescript/src/types/NativeSamplingOptions.d.ts +7 -0
- package/lib/typescript/src/types/ReadOptions.d.ts +7 -0
- package/lib/typescript/src/types/RecordingOptions.d.ts +11 -0
- package/lib/typescript/src/types/RecordingStats.d.ts +25 -0
- package/lib/typescript/src/types/SpanEvent.d.ts +13 -0
- package/lib/typescript/src/types/SpanOptions.d.ts +6 -0
- package/lib/typescript/src/types/SpanOutcome.d.ts +2 -0
- package/lib/typescript/src/types/TraceAttribute.d.ts +7 -0
- package/lib/typescript/src/types/TraceAttributes.d.ts +3 -0
- package/lib/typescript/src/types/TraceContext.d.ts +10 -0
- package/lib/typescript/src/types/TracePage.d.ts +18 -0
- package/lib/typescript/src/types.d.ts +17 -0
- package/nitro.json +20 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NitroTracing+autolinking.cmake +83 -0
- package/nitrogen/generated/android/NitroTracing+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NitroTracingOnLoad.cpp +49 -0
- package/nitrogen/generated/android/NitroTracingOnLoad.hpp +34 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrotracing/NitroTracingOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NitroTracing+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/NitroTracingAutolinking.mm +35 -0
- package/nitrogen/generated/ios/NitroTracingAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/CompletedSpanOptions.hpp +122 -0
- package/nitrogen/generated/shared/c++/HybridRecordingSpec.cpp +31 -0
- package/nitrogen/generated/shared/c++/HybridRecordingSpec.hpp +100 -0
- package/nitrogen/generated/shared/c++/HybridTraceSpanSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridTraceSpanSpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridTracingSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridTracingSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/MarkEvent.hpp +102 -0
- package/nitrogen/generated/shared/c++/MarkOptions.hpp +99 -0
- package/nitrogen/generated/shared/c++/MetricEvent.hpp +110 -0
- package/nitrogen/generated/shared/c++/MetricOptions.hpp +107 -0
- package/nitrogen/generated/shared/c++/NativeSamplingOptions.hpp +87 -0
- package/nitrogen/generated/shared/c++/ReadOptions.hpp +87 -0
- package/nitrogen/generated/shared/c++/RecordingOptions.hpp +95 -0
- package/nitrogen/generated/shared/c++/RecordingStats.hpp +123 -0
- package/nitrogen/generated/shared/c++/SpanEvent.hpp +121 -0
- package/nitrogen/generated/shared/c++/SpanOptions.hpp +99 -0
- package/nitrogen/generated/shared/c++/SpanOutcome.hpp +84 -0
- package/nitrogen/generated/shared/c++/TraceAttribute.hpp +87 -0
- package/nitrogen/generated/shared/c++/TracePage.hpp +111 -0
- package/package.json +236 -0
- package/performance.ts +2 -0
- package/plugins.ts +24 -0
- package/react-native.config.js +16 -0
- package/react.ts +10 -0
- package/release-profiler.ts +6 -0
- package/sentry.ts +2 -0
- package/src/client/TracingSink.ts +25 -0
- package/src/client/createTraceClient.ts +439 -0
- package/src/client/playground.ts +143 -0
- package/src/expo/ExpoAdapter.ts +71 -0
- package/src/expo/index.ts +2 -0
- package/src/index.ts +8 -0
- package/src/plugins/TracePlugin.ts +22 -0
- package/src/plugins/errors.ts +69 -0
- package/src/plugins/nativeMetrics.ts +26 -0
- package/src/plugins/navigation.ts +111 -0
- package/src/plugins/network.ts +178 -0
- package/src/plugins/orderSpans.ts +22 -0
- package/src/plugins/performance.ts +120 -0
- package/src/plugins/releaseProfiler.ts +123 -0
- package/src/plugins/runtimeMetrics.ts +131 -0
- package/src/plugins/sentry.ts +176 -0
- package/src/plugins/startPlugins.ts +58 -0
- package/src/react/DetailView.tsx +514 -0
- package/src/react/ExplorerFilters.tsx +151 -0
- package/src/react/ExplorerView.tsx +243 -0
- package/src/react/InspectorControls.tsx +651 -0
- package/src/react/InspectorHeader.tsx +171 -0
- package/src/react/InspectorSheet.tsx +89 -0
- package/src/react/MetricsView.tsx +182 -0
- package/src/react/SummaryView.tsx +121 -0
- package/src/react/TimelineView.tsx +87 -0
- package/src/react/TraceInspector.tsx +196 -0
- package/src/react/TraceOverlay.tsx +585 -0
- package/src/react/explorerModel.ts +285 -0
- package/src/react/labels.ts +234 -0
- package/src/react/native.tsx +159 -0
- package/src/react/readSnapshot.ts +58 -0
- package/src/react/store.ts +31 -0
- package/src/react/topics.ts +427 -0
- package/src/react/useAppReadyMetric.ts +10 -0
- package/src/react/useLiveRecording.ts +43 -0
- package/src/react/useTraceViewer.ts +333 -0
- package/src/react/viewerModel.ts +172 -0
- package/src/specs/Recording.nitro.ts +40 -0
- package/src/specs/TraceSpan.nitro.ts +14 -0
- package/src/specs/Tracing.nitro.ts +14 -0
- package/src/types/CompletedSpanOptions.ts +15 -0
- package/src/types/EventContext.ts +8 -0
- package/src/types/MarkEvent.ts +3 -0
- package/src/types/MarkOptions.ts +6 -0
- package/src/types/MetricEvent.ts +8 -0
- package/src/types/MetricOptions.ts +10 -0
- package/src/types/NativeSamplingOptions.ts +7 -0
- package/src/types/ReadOptions.ts +7 -0
- package/src/types/RecordingOptions.ts +11 -0
- package/src/types/RecordingStats.ts +25 -0
- package/src/types/SpanEvent.ts +13 -0
- package/src/types/SpanOptions.ts +6 -0
- package/src/types/SpanOutcome.ts +2 -0
- package/src/types/TraceAttribute.ts +7 -0
- package/src/types/TraceAttributes.ts +4 -0
- package/src/types/TraceContext.ts +10 -0
- package/src/types/TracePage.ts +18 -0
- package/src/types.ts +17 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { createStore } from './store'
|
|
2
|
+
import { readSnapshot } from './readSnapshot'
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useDeferredValue,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
useState,
|
|
10
|
+
useSyncExternalStore,
|
|
11
|
+
} from 'react'
|
|
12
|
+
import type { TraceClient } from '../client/createTraceClient'
|
|
13
|
+
import type { RecordingStats, TracePage, SpanEvent, MarkEvent } from '../types'
|
|
14
|
+
import {
|
|
15
|
+
buildTraces,
|
|
16
|
+
defaultQuery,
|
|
17
|
+
queryEvents,
|
|
18
|
+
queryTraces,
|
|
19
|
+
traceForSpan,
|
|
20
|
+
type ExplorerMode,
|
|
21
|
+
type Query,
|
|
22
|
+
type Trace,
|
|
23
|
+
} from './explorerModel'
|
|
24
|
+
import { recordingMetrics, operationMetrics } from './viewerModel'
|
|
25
|
+
import {
|
|
26
|
+
buildTimeline,
|
|
27
|
+
currentScreen,
|
|
28
|
+
defaultBudgets,
|
|
29
|
+
summarizeTopics,
|
|
30
|
+
type Budgets,
|
|
31
|
+
} from './topics'
|
|
32
|
+
export type Metric = ReturnType<typeof recordingMetrics>[number]
|
|
33
|
+
export type Detail =
|
|
34
|
+
| { kind: 'trace'; value: Trace }
|
|
35
|
+
| { kind: 'span'; value: SpanEvent }
|
|
36
|
+
| { kind: 'mark'; value: MarkEvent }
|
|
37
|
+
| { kind: 'metric'; value: Metric }
|
|
38
|
+
export type Tab = 'overview' | 'timeline' | 'explore' | 'metrics' | 'tools'
|
|
39
|
+
export interface Telemetry {
|
|
40
|
+
stats?: RecordingStats
|
|
41
|
+
error?: string
|
|
42
|
+
pending?: Pick<TracePage, 'nextSequence' | 'earliestSequence'>
|
|
43
|
+
}
|
|
44
|
+
const empty = (): TracePage => ({
|
|
45
|
+
spans: [],
|
|
46
|
+
marks: [],
|
|
47
|
+
metrics: [],
|
|
48
|
+
nextSequence: 0,
|
|
49
|
+
earliestSequence: 0,
|
|
50
|
+
droppedEvents: 0,
|
|
51
|
+
})
|
|
52
|
+
export const useTraceViewer = (
|
|
53
|
+
client: TraceClient,
|
|
54
|
+
budgets?: Partial<Budgets>
|
|
55
|
+
) => {
|
|
56
|
+
const snapshot = useSyncExternalStore(
|
|
57
|
+
client.subscribe,
|
|
58
|
+
client.getSnapshot,
|
|
59
|
+
client.getSnapshot
|
|
60
|
+
)
|
|
61
|
+
const [tab, setTab] = useState<Tab>('overview')
|
|
62
|
+
const [mode, setMode] = useState<ExplorerMode>('traces')
|
|
63
|
+
const [page, setPage] = useState(empty)
|
|
64
|
+
const [telemetry] = useState(() => createStore<Telemetry>({}))
|
|
65
|
+
const setStats = (stats: RecordingStats) => telemetry.set({ stats })
|
|
66
|
+
const setError = (error: string | undefined) => telemetry.set({ error })
|
|
67
|
+
const pendingPage = useRef<TracePage | undefined>(undefined)
|
|
68
|
+
const setPending = (value: TracePage | undefined) => {
|
|
69
|
+
pendingPage.current = value
|
|
70
|
+
telemetry.set({
|
|
71
|
+
pending: value
|
|
72
|
+
? {
|
|
73
|
+
nextSequence: value.nextSequence,
|
|
74
|
+
earliestSequence: value.earliestSequence,
|
|
75
|
+
}
|
|
76
|
+
: undefined,
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
const [queries, setQueries] = useState<Record<ExplorerMode, Query>>({
|
|
80
|
+
traces: defaultQuery(),
|
|
81
|
+
spans: defaultQuery(),
|
|
82
|
+
marks: defaultQuery(),
|
|
83
|
+
})
|
|
84
|
+
const [details, setDetails] = useState<Detail[]>([])
|
|
85
|
+
const [paused, setPaused] = useState(false)
|
|
86
|
+
const [holding, setHolding] = useState(false)
|
|
87
|
+
const [metricQuery, setMetricQuery] = useState('')
|
|
88
|
+
const [metricCategory, setMetricCategory] = useState('all')
|
|
89
|
+
const [metricSort, setMetricSort] = useState('name')
|
|
90
|
+
const offsets = useRef<Record<string, number>>({})
|
|
91
|
+
const detailState = useRef<
|
|
92
|
+
Record<
|
|
93
|
+
string,
|
|
94
|
+
{
|
|
95
|
+
collapsed: string[]
|
|
96
|
+
layout: 'waterfall' | 'list'
|
|
97
|
+
attributes: string
|
|
98
|
+
offset: number
|
|
99
|
+
}
|
|
100
|
+
>
|
|
101
|
+
>({})
|
|
102
|
+
const latestPage = useRef(page)
|
|
103
|
+
const session = useRef<string | undefined>(undefined)
|
|
104
|
+
const controls = useRef({ paused, holding, detail: details.length > 0 })
|
|
105
|
+
controls.current = { paused, holding, detail: details.length > 0 }
|
|
106
|
+
latestPage.current = page
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (!snapshot.visible) return
|
|
109
|
+
let cached: TracePage | undefined
|
|
110
|
+
let cachedRecording: ReturnType<TraceClient['getRecording']>
|
|
111
|
+
let cancelled = false
|
|
112
|
+
let timer: ReturnType<typeof setTimeout>
|
|
113
|
+
const refresh = async () => {
|
|
114
|
+
try {
|
|
115
|
+
const recording = client.getRecording()
|
|
116
|
+
if (recording) {
|
|
117
|
+
if (cachedRecording !== recording) {
|
|
118
|
+
cached = undefined
|
|
119
|
+
cachedRecording = recording
|
|
120
|
+
}
|
|
121
|
+
const next = await readSnapshot(recording, cached)
|
|
122
|
+
cached = next
|
|
123
|
+
if (cancelled || recording !== client.getRecording()) return
|
|
124
|
+
const current = recording.getStats()
|
|
125
|
+
setStats(current)
|
|
126
|
+
if (session.current !== current.sessionId) {
|
|
127
|
+
session.current = current.sessionId
|
|
128
|
+
setDetails([])
|
|
129
|
+
setPending(undefined)
|
|
130
|
+
setPage(next)
|
|
131
|
+
setHolding(false)
|
|
132
|
+
offsets.current = {}
|
|
133
|
+
detailState.current = {}
|
|
134
|
+
setQueries(
|
|
135
|
+
(previous) =>
|
|
136
|
+
Object.fromEntries(
|
|
137
|
+
Object.entries(previous).map(([key, q]) => [
|
|
138
|
+
key,
|
|
139
|
+
{ ...q, from: '', to: '' },
|
|
140
|
+
])
|
|
141
|
+
) as Record<ExplorerMode, Query>
|
|
142
|
+
)
|
|
143
|
+
} else if (
|
|
144
|
+
controls.current.paused ||
|
|
145
|
+
controls.current.holding ||
|
|
146
|
+
controls.current.detail
|
|
147
|
+
) {
|
|
148
|
+
if (
|
|
149
|
+
next.nextSequence !== latestPage.current.nextSequence ||
|
|
150
|
+
next.droppedEvents !== latestPage.current.droppedEvents
|
|
151
|
+
)
|
|
152
|
+
setPending(next)
|
|
153
|
+
} else {
|
|
154
|
+
setPage(next)
|
|
155
|
+
setPending(undefined)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!cancelled) setError(client.getError())
|
|
159
|
+
} catch (failure) {
|
|
160
|
+
if (!cancelled) setError(String(failure))
|
|
161
|
+
} finally {
|
|
162
|
+
if (!cancelled) timer = setTimeout(refresh, 1000)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
void refresh()
|
|
166
|
+
return () => {
|
|
167
|
+
cancelled = true
|
|
168
|
+
clearTimeout(timer)
|
|
169
|
+
}
|
|
170
|
+
}, [client, snapshot.visible])
|
|
171
|
+
const traces = useMemo(() => buildTraces(page), [page.spans, page.marks])
|
|
172
|
+
const metrics = useMemo(
|
|
173
|
+
() => (tab === 'explore' ? [] : recordingMetrics(page)),
|
|
174
|
+
[page, tab]
|
|
175
|
+
)
|
|
176
|
+
const collectors = snapshot.collectors
|
|
177
|
+
const { appReadyMs, screenMs, requestMs, stallMs } = {
|
|
178
|
+
...defaultBudgets,
|
|
179
|
+
...budgets,
|
|
180
|
+
}
|
|
181
|
+
const summary = useMemo(
|
|
182
|
+
() =>
|
|
183
|
+
summarizeTopics(page, collectors ?? [], {
|
|
184
|
+
appReadyMs,
|
|
185
|
+
screenMs,
|
|
186
|
+
requestMs,
|
|
187
|
+
stallMs,
|
|
188
|
+
}),
|
|
189
|
+
[page, collectors, appReadyMs, screenMs, requestMs, stallMs]
|
|
190
|
+
)
|
|
191
|
+
const timeline = useMemo(
|
|
192
|
+
() => (tab === 'timeline' ? buildTimeline(page, summary.issues) : []),
|
|
193
|
+
[page, summary.issues, tab]
|
|
194
|
+
)
|
|
195
|
+
const screen = useMemo(() => currentScreen(page), [page.marks])
|
|
196
|
+
const operations = useMemo(
|
|
197
|
+
() => (tab === 'metrics' ? operationMetrics(page.spans) : []),
|
|
198
|
+
[page.spans, tab]
|
|
199
|
+
)
|
|
200
|
+
const query = queries[mode]
|
|
201
|
+
const deferredQuery = useDeferredValue(query)
|
|
202
|
+
const results = useMemo(
|
|
203
|
+
() =>
|
|
204
|
+
mode === 'traces'
|
|
205
|
+
? queryTraces(traces, deferredQuery)
|
|
206
|
+
: queryEvents(
|
|
207
|
+
mode === 'spans' ? page.spans : page.marks,
|
|
208
|
+
deferredQuery
|
|
209
|
+
),
|
|
210
|
+
[mode, traces, page.spans, page.marks, deferredQuery]
|
|
211
|
+
)
|
|
212
|
+
const updateQuery = (patch: Partial<Query>) => {
|
|
213
|
+
setHolding(true)
|
|
214
|
+
setQueries((previous) => ({
|
|
215
|
+
...previous,
|
|
216
|
+
[mode]: { ...previous[mode], ...patch },
|
|
217
|
+
}))
|
|
218
|
+
offsets.current[mode] = 0
|
|
219
|
+
}
|
|
220
|
+
const apply = () => {
|
|
221
|
+
const pending = pendingPage.current
|
|
222
|
+
if (pending) setPage(pending)
|
|
223
|
+
setPending(undefined)
|
|
224
|
+
setHolding(false)
|
|
225
|
+
}
|
|
226
|
+
const act = (work: () => void | Promise<void>) => {
|
|
227
|
+
void Promise.resolve()
|
|
228
|
+
.then(work)
|
|
229
|
+
.catch((failure) => {
|
|
230
|
+
setError(String(failure))
|
|
231
|
+
client.reportError(failure)
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
const detail = details[details.length - 1]
|
|
235
|
+
// Stable identity lets memoized list rows skip re-rendering on live ticks.
|
|
236
|
+
const open = useCallback((next: Detail) => {
|
|
237
|
+
setHolding(true)
|
|
238
|
+
setDetails((previous) => [...previous.slice(-31), next])
|
|
239
|
+
}, [])
|
|
240
|
+
const showEvents = (mode: 'spans' | 'marks', patch: Partial<Query>) => {
|
|
241
|
+
setTab('explore')
|
|
242
|
+
setMode(mode)
|
|
243
|
+
setDetails([])
|
|
244
|
+
setQueries((previous) => ({
|
|
245
|
+
...previous,
|
|
246
|
+
[mode]: { ...defaultQuery(), ...patch },
|
|
247
|
+
}))
|
|
248
|
+
offsets.current[mode] = 0
|
|
249
|
+
setHolding(true)
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
...snapshot,
|
|
253
|
+
client,
|
|
254
|
+
tab,
|
|
255
|
+
setTab: (next: Tab) => {
|
|
256
|
+
setDetails([])
|
|
257
|
+
setTab(next)
|
|
258
|
+
},
|
|
259
|
+
mode,
|
|
260
|
+
setMode,
|
|
261
|
+
page,
|
|
262
|
+
telemetry,
|
|
263
|
+
traces,
|
|
264
|
+
topics: summary.topics,
|
|
265
|
+
issues: summary.issues,
|
|
266
|
+
timeline,
|
|
267
|
+
screen,
|
|
268
|
+
results,
|
|
269
|
+
query,
|
|
270
|
+
updateQuery,
|
|
271
|
+
resetQuery: () => {
|
|
272
|
+
setQueries((previous) => ({ ...previous, [mode]: defaultQuery() }))
|
|
273
|
+
offsets.current[mode] = 0
|
|
274
|
+
},
|
|
275
|
+
loaded:
|
|
276
|
+
mode === 'traces'
|
|
277
|
+
? traces.length
|
|
278
|
+
: mode === 'spans'
|
|
279
|
+
? page.spans.length
|
|
280
|
+
: page.marks.length,
|
|
281
|
+
uncorrelated: useMemo(
|
|
282
|
+
() =>
|
|
283
|
+
page.spans.filter((s) => !s.correlationId).length +
|
|
284
|
+
page.marks.filter((s) => !s.correlationId).length,
|
|
285
|
+
[page.spans, page.marks]
|
|
286
|
+
),
|
|
287
|
+
detail,
|
|
288
|
+
detailState,
|
|
289
|
+
details,
|
|
290
|
+
open,
|
|
291
|
+
back: () => setDetails((previous) => previous.slice(0, -1)),
|
|
292
|
+
traceFor: (span: SpanEvent) => traceForSpan(traces, span),
|
|
293
|
+
showSpans: (patch: Partial<Query>) => showEvents('spans', patch),
|
|
294
|
+
showMarks: (patch: Partial<Query>) => showEvents('marks', patch),
|
|
295
|
+
paused,
|
|
296
|
+
holding,
|
|
297
|
+
setHolding,
|
|
298
|
+
apply,
|
|
299
|
+
togglePause: () => {
|
|
300
|
+
if (paused) apply()
|
|
301
|
+
setPaused(!paused)
|
|
302
|
+
},
|
|
303
|
+
offsets,
|
|
304
|
+
metrics,
|
|
305
|
+
operations,
|
|
306
|
+
metricQuery,
|
|
307
|
+
setMetricQuery,
|
|
308
|
+
metricCategory,
|
|
309
|
+
setMetricCategory,
|
|
310
|
+
metricSort,
|
|
311
|
+
setMetricSort,
|
|
312
|
+
start: () => act(client.start),
|
|
313
|
+
stop: () => act(client.stop),
|
|
314
|
+
export: () => act(client.export),
|
|
315
|
+
sharePerfetto: () => act(() => client.shareTrace('perfetto')),
|
|
316
|
+
toggleProfile: () => act(client.toggleProfile),
|
|
317
|
+
shareProfile: () => act(client.shareProfile),
|
|
318
|
+
playground: () => act(client.playground),
|
|
319
|
+
playgroundResult: snapshot.playground,
|
|
320
|
+
openPlayground: () => {
|
|
321
|
+
setTab('explore')
|
|
322
|
+
setMode('traces')
|
|
323
|
+
setQueries((previous) => ({
|
|
324
|
+
...previous,
|
|
325
|
+
traces: {
|
|
326
|
+
...defaultQuery(),
|
|
327
|
+
correlation: snapshot.playground?.correlationId ?? '',
|
|
328
|
+
},
|
|
329
|
+
}))
|
|
330
|
+
},
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
export type Viewer = ReturnType<typeof useTraceViewer>
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { MetricEvent, SpanEvent, TracePage } from '../types'
|
|
2
|
+
export interface TraceGroup {
|
|
3
|
+
id: string
|
|
4
|
+
name: string
|
|
5
|
+
start: number
|
|
6
|
+
duration: number
|
|
7
|
+
errors: number
|
|
8
|
+
events: number
|
|
9
|
+
}
|
|
10
|
+
export const groupTraces = (page: TracePage, query: string): TraceGroup[] => {
|
|
11
|
+
const groups = new Map<string, TraceGroup>()
|
|
12
|
+
for (const event of [...page.spans, ...page.marks, ...page.metrics]) {
|
|
13
|
+
const id = event.correlationId || 'uncorrelated'
|
|
14
|
+
const end =
|
|
15
|
+
event.timestampMs +
|
|
16
|
+
('durationMs' in event && typeof event.durationMs === 'number'
|
|
17
|
+
? event.durationMs
|
|
18
|
+
: 0)
|
|
19
|
+
const previous = groups.get(id)
|
|
20
|
+
const start = Math.min(
|
|
21
|
+
previous?.start ?? event.timestampMs,
|
|
22
|
+
event.timestampMs
|
|
23
|
+
)
|
|
24
|
+
groups.set(id, {
|
|
25
|
+
id,
|
|
26
|
+
name:
|
|
27
|
+
previous && previous.start <= event.timestampMs
|
|
28
|
+
? previous.name
|
|
29
|
+
: event.name,
|
|
30
|
+
start,
|
|
31
|
+
duration:
|
|
32
|
+
Math.max(previous ? previous.start + previous.duration : end, end) -
|
|
33
|
+
start,
|
|
34
|
+
errors:
|
|
35
|
+
(previous?.errors ?? 0) +
|
|
36
|
+
('outcome' in event && event.outcome === 'error' ? 1 : 0),
|
|
37
|
+
events: (previous?.events ?? 0) + 1,
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
const search = query.toLowerCase()
|
|
41
|
+
const matchingIds = new Set(
|
|
42
|
+
[...page.spans, ...page.marks, ...page.metrics]
|
|
43
|
+
.filter((event) =>
|
|
44
|
+
`${event.name} ${event.correlationId}`.toLowerCase().includes(search)
|
|
45
|
+
)
|
|
46
|
+
.map((event) => event.correlationId || 'uncorrelated')
|
|
47
|
+
)
|
|
48
|
+
return [...groups.values()]
|
|
49
|
+
.filter((group) => !search || matchingIds.has(group.id))
|
|
50
|
+
.sort((a, b) => b.start - a.start)
|
|
51
|
+
}
|
|
52
|
+
export const waterfall = (spans: SpanEvent[]) => {
|
|
53
|
+
const byId = new Map(spans.map((span) => [span.spanId, span]))
|
|
54
|
+
const base = spans.length
|
|
55
|
+
? Math.min(...spans.map((span) => span.timestampMs))
|
|
56
|
+
: 0
|
|
57
|
+
const duration = Math.max(
|
|
58
|
+
1,
|
|
59
|
+
...spans.map((span) => span.timestampMs + span.durationMs - base)
|
|
60
|
+
)
|
|
61
|
+
return [...spans]
|
|
62
|
+
.sort(
|
|
63
|
+
(a, b) => a.timestampMs - b.timestampMs || b.durationMs - a.durationMs
|
|
64
|
+
)
|
|
65
|
+
.map((span) => {
|
|
66
|
+
const seen = new Set([span.spanId])
|
|
67
|
+
let parent = byId.get(span.parentSpanId)
|
|
68
|
+
let depth = 0
|
|
69
|
+
while (parent && depth < 8 && !seen.has(parent.spanId)) {
|
|
70
|
+
seen.add(parent.spanId)
|
|
71
|
+
depth++
|
|
72
|
+
parent = byId.get(parent.parentSpanId)
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
span,
|
|
76
|
+
depth: Math.min(depth, 8),
|
|
77
|
+
offset: (span.timestampMs - base) / duration,
|
|
78
|
+
width: span.durationMs / duration,
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
const num = (value: number) =>
|
|
83
|
+
Math.abs(value) >= 100 ? value.toFixed(0) : value.toFixed(1)
|
|
84
|
+
/** Human value with unit: 3653 ms → "3.65 s", 1240 MB → "1.21 GB". */
|
|
85
|
+
export const formatMetric = (value: number, unit: string) => {
|
|
86
|
+
if (unit === 'ms' && Math.abs(value) >= 1000)
|
|
87
|
+
return `${(value / 1000).toFixed(2)} s`
|
|
88
|
+
if (unit === 'MB' && Math.abs(value) >= 1024)
|
|
89
|
+
return `${(value / 1024).toFixed(2)} GB`
|
|
90
|
+
if (unit === 'count') return value.toFixed(0)
|
|
91
|
+
if (unit === '%') return `${num(value)}%`
|
|
92
|
+
if (unit.endsWith('/s')) return `${num(value)}/s`
|
|
93
|
+
return `${num(value)} ${unit}`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const metricSeries = (metrics: MetricEvent[]) => {
|
|
97
|
+
const groups = new Map<string, MetricEvent[]>()
|
|
98
|
+
for (const metric of metrics) {
|
|
99
|
+
const key = `${metric.name} (${metric.unit})`
|
|
100
|
+
const group = groups.get(key) ?? []
|
|
101
|
+
group.push(metric)
|
|
102
|
+
groups.set(key, group)
|
|
103
|
+
}
|
|
104
|
+
return [...groups].map(([name, retained]) => {
|
|
105
|
+
const samples = retained
|
|
106
|
+
.sort((a, b) => a.timestampMs - b.timestampMs)
|
|
107
|
+
.slice(-40)
|
|
108
|
+
const values = retained.map((sample) => sample.value).sort((a, b) => a - b)
|
|
109
|
+
return {
|
|
110
|
+
latest: retained[retained.length - 1]?.value ?? 0,
|
|
111
|
+
median: values.length
|
|
112
|
+
? (values[Math.floor((values.length - 1) / 2)] +
|
|
113
|
+
values[Math.ceil((values.length - 1) / 2)]) /
|
|
114
|
+
2
|
|
115
|
+
: 0,
|
|
116
|
+
min: values[0] ?? 0,
|
|
117
|
+
peak: values[values.length - 1] ?? 0,
|
|
118
|
+
p95: values[Math.max(0, Math.ceil(values.length * 0.95) - 1)] ?? 0,
|
|
119
|
+
name,
|
|
120
|
+
/** Metric name without the unit suffix used for grouping. */
|
|
121
|
+
metric: retained[0].name,
|
|
122
|
+
unit: retained[0].unit,
|
|
123
|
+
samples,
|
|
124
|
+
retainedCount: retained.length,
|
|
125
|
+
startMs: samples[0]?.timestampMs ?? 0,
|
|
126
|
+
endMs: samples[samples.length - 1]?.timestampMs ?? 0,
|
|
127
|
+
max: Math.max(1, ...samples.map((sample) => Math.abs(sample.value))),
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Durations are derived from retained completed spans, not additional native samples. */
|
|
133
|
+
export const recordingMetrics = (page: TracePage) =>
|
|
134
|
+
metricSeries([
|
|
135
|
+
...page.metrics,
|
|
136
|
+
...page.spans
|
|
137
|
+
.filter((span) => span.outcome === 'success' || span.outcome === 'error')
|
|
138
|
+
.map((span) => ({
|
|
139
|
+
...span,
|
|
140
|
+
name: `duration: ${span.name}`,
|
|
141
|
+
value: span.durationMs,
|
|
142
|
+
unit: 'ms',
|
|
143
|
+
})),
|
|
144
|
+
])
|
|
145
|
+
|
|
146
|
+
export const operationMetrics = (spans: SpanEvent[]) => {
|
|
147
|
+
const groups = new Map<string, SpanEvent[]>()
|
|
148
|
+
for (const span of spans) {
|
|
149
|
+
const group = groups.get(span.name) ?? []
|
|
150
|
+
group.push(span)
|
|
151
|
+
groups.set(span.name, group)
|
|
152
|
+
}
|
|
153
|
+
return [...groups]
|
|
154
|
+
.map(([name, samples]) => {
|
|
155
|
+
const completed = samples.filter(
|
|
156
|
+
(s) => s.outcome === 'success' || s.outcome === 'error'
|
|
157
|
+
)
|
|
158
|
+
return {
|
|
159
|
+
name,
|
|
160
|
+
count: samples.length,
|
|
161
|
+
errors: completed.filter((s) => s.outcome === 'error').length,
|
|
162
|
+
errorRate: completed.length
|
|
163
|
+
? (completed.filter((s) => s.outcome === 'error').length /
|
|
164
|
+
completed.length) *
|
|
165
|
+
100
|
|
166
|
+
: undefined,
|
|
167
|
+
cancelled: samples.filter((s) => s.outcome === 'cancelled').length,
|
|
168
|
+
interrupted: samples.filter((s) => s.outcome === 'interrupted').length,
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
.sort((a, b) => b.count - a.count)
|
|
172
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
import type { TraceSpan } from './TraceSpan.nitro'
|
|
3
|
+
import type {
|
|
4
|
+
CompletedSpanOptions,
|
|
5
|
+
SpanOptions,
|
|
6
|
+
MarkOptions,
|
|
7
|
+
MetricOptions,
|
|
8
|
+
ReadOptions,
|
|
9
|
+
TracePage,
|
|
10
|
+
RecordingStats,
|
|
11
|
+
NativeSamplingOptions,
|
|
12
|
+
} from '../types'
|
|
13
|
+
/** Owns bounded native history. Stop before export; dispose when all readers are done. */
|
|
14
|
+
export interface Recording extends HybridObject<{
|
|
15
|
+
ios: 'c++'
|
|
16
|
+
android: 'c++'
|
|
17
|
+
}> {
|
|
18
|
+
/** Start a span, optionally linked to an explicit parent. */
|
|
19
|
+
startSpan(options: SpanOptions): TraceSpan
|
|
20
|
+
/** Import a completed measurement; returns its native span identity. */
|
|
21
|
+
recordSpan(options: CompletedSpanOptions): string
|
|
22
|
+
/** Append a point event. */
|
|
23
|
+
mark(options: MarkOptions): void
|
|
24
|
+
/** Append a finite numeric sample with units. */
|
|
25
|
+
recordMetric(options: MetricOptions): void
|
|
26
|
+
/** Read at most 1000 completed events without per-event callbacks. */
|
|
27
|
+
readEvents(options: ReadOptions): Promise<TracePage>
|
|
28
|
+
/** Read cheap recording counters and clock anchor. */
|
|
29
|
+
getStats(): RecordingStats
|
|
30
|
+
/** Freeze history and close active spans as interrupted. Idempotent. */
|
|
31
|
+
stop(): void
|
|
32
|
+
/** Serialize a snapshot off the JS thread; includes schema version and clock anchor. */
|
|
33
|
+
exportJson(): Promise<string>
|
|
34
|
+
/** Chrome Trace Event JSON for ui.perfetto.dev; serialized off the JS thread. */
|
|
35
|
+
exportTraceEvents(): Promise<string>
|
|
36
|
+
/** Start a native thread writing process.cpu, process.memory and ui.* frame metrics. Replaces a running sampler. */
|
|
37
|
+
startNativeSampling(options: NativeSamplingOptions): void
|
|
38
|
+
/** Stop native sampling. Idempotent; stop() and dispose() also stop it. */
|
|
39
|
+
stopNativeSampling(): void
|
|
40
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
import type { SpanOutcome } from '../types'
|
|
3
|
+
/** A native span handle returned by Recording.startSpan. */
|
|
4
|
+
export interface TraceSpan extends HybridObject<{
|
|
5
|
+
ios: 'c++'
|
|
6
|
+
android: 'c++'
|
|
7
|
+
}> {
|
|
8
|
+
/** Empty when rejected by capacity limits. */
|
|
9
|
+
readonly spanId: string
|
|
10
|
+
/** Whether capacity allowed this span to be recorded. */
|
|
11
|
+
readonly recorded: boolean
|
|
12
|
+
/** Complete once. Repeated completion and completion after stop are no-ops. */
|
|
13
|
+
end(outcome: SpanOutcome): void
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
import type { Recording } from './Recording.nitro'
|
|
3
|
+
import type { RecordingOptions } from '../types'
|
|
4
|
+
/** Factory for independent native recordings. Exported as Tracing. */
|
|
5
|
+
export interface Tracing extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
6
|
+
/** Create an active recording with explicit validated retention limits. */
|
|
7
|
+
startRecording(options: RecordingOptions): Recording
|
|
8
|
+
/**
|
|
9
|
+
* Stop Hermes' process-wide sampling profiler. The release-profiler plugin calls this
|
|
10
|
+
* after saving a profile: on React Native 0.85 Android the profiler's own stop restarts
|
|
11
|
+
* sampling. Returns false where Hermes is not linked (iOS stops correctly itself).
|
|
12
|
+
*/
|
|
13
|
+
disableHermesSampling(): boolean
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SpanOutcome } from './SpanOutcome'
|
|
2
|
+
import type { SpanOptions } from './SpanOptions'
|
|
3
|
+
/** Completed external measurement in Recording's native clock domain. */
|
|
4
|
+
export interface CompletedSpanOptions extends SpanOptions {
|
|
5
|
+
/** Optional source-qualified identity, for example sentry:traceId:spanId. */
|
|
6
|
+
sourceSpanId?: string
|
|
7
|
+
/** Source-qualified parent identity; resolves even when parent ends later. */
|
|
8
|
+
sourceParentSpanId?: string
|
|
9
|
+
/** Start in milliseconds relative to recording creation. */
|
|
10
|
+
timestampMs: number
|
|
11
|
+
/** Finite nonnegative duration. */
|
|
12
|
+
durationMs: number
|
|
13
|
+
/** Terminal result from the measurement source. */
|
|
14
|
+
outcome: SpanOutcome
|
|
15
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TraceContext } from './TraceContext'
|
|
2
|
+
/** Immutable native event identity and timing shared by recorded variants. */
|
|
3
|
+
export interface EventContext extends TraceContext {
|
|
4
|
+
/** Increasing session-local completion sequence. */
|
|
5
|
+
sequence: number
|
|
6
|
+
/** Milliseconds since recording creation on its native monotonic clock. */
|
|
7
|
+
timestampMs: number
|
|
8
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TraceContext } from './TraceContext'
|
|
2
|
+
/** Native mark, optionally imported with a translated source timestamp. */
|
|
3
|
+
export interface MarkOptions extends TraceContext {
|
|
4
|
+
/** Milliseconds in the recording clock; omit to record now. */
|
|
5
|
+
timestampMs?: number
|
|
6
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TraceContext } from './TraceContext'
|
|
2
|
+
/** Input to Recording.recordMetric. */
|
|
3
|
+
export interface MetricOptions extends TraceContext {
|
|
4
|
+
/** Optional source timestamp translated to the recording clock. */
|
|
5
|
+
timestampMs?: number
|
|
6
|
+
/** Finite numeric sample. */
|
|
7
|
+
value: number
|
|
8
|
+
/** Unit, for example bytes, byte/second, count, millisecond. */
|
|
9
|
+
unit: string
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Native sampler settings for Recording.startNativeSampling. */
|
|
2
|
+
export interface NativeSamplingOptions {
|
|
3
|
+
/** Window length for CPU, memory and frame metrics; 250–60000 ms. */
|
|
4
|
+
intervalMs: number
|
|
5
|
+
/** Observe main-thread display callbacks (CADisplayLink / Choreographer). */
|
|
6
|
+
frames: boolean
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Bounded page query for Recording.readEvents; sequence zero starts at history. */
|
|
2
|
+
export interface ReadOptions {
|
|
3
|
+
/** Exclusive completion sequence cursor. */
|
|
4
|
+
afterSequence: number
|
|
5
|
+
/** Maximum total events returned across all arrays; 1–1000. */
|
|
6
|
+
limit: number
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Native retention limits for Tracing.startRecording. All fields are required. */
|
|
2
|
+
export interface RecordingOptions {
|
|
3
|
+
/** Maximum completed events retained; 1–100000. */
|
|
4
|
+
maxEvents: number
|
|
5
|
+
/** Retained payload budget including active spans; 1024–67108864 bytes. */
|
|
6
|
+
maxBytes: number
|
|
7
|
+
/** Maximum simultaneously active spans; 1–10000. */
|
|
8
|
+
maxActiveSpans: number
|
|
9
|
+
/** Expire abandoned spans on the next recorder access; milliseconds. */
|
|
10
|
+
spanTimeoutMs: number
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Snapshot of a recording, returned by Recording.getStats. */
|
|
2
|
+
export interface RecordingStats {
|
|
3
|
+
/** Recording identity. */
|
|
4
|
+
sessionId: string
|
|
5
|
+
/** Wall-clock anchor in Unix milliseconds, for correlation/export only. */
|
|
6
|
+
startedAtUnixMs: number
|
|
7
|
+
/** Native elapsed milliseconds at snapshot time. */
|
|
8
|
+
nowMs: number
|
|
9
|
+
/** Whether writes are accepted. */
|
|
10
|
+
recording: boolean
|
|
11
|
+
/** Retained completed events. */
|
|
12
|
+
eventCount: number
|
|
13
|
+
/** Accounted native payload bytes, including active spans. */
|
|
14
|
+
retainedBytes: number
|
|
15
|
+
/** Evicted or rejected event/span count. */
|
|
16
|
+
droppedEvents: number
|
|
17
|
+
/** Open spans. */
|
|
18
|
+
activeSpans: number
|
|
19
|
+
/** Evicted or rejected spans (part of droppedEvents). */
|
|
20
|
+
droppedSpans: number
|
|
21
|
+
/** Evicted or rejected marks (part of droppedEvents). */
|
|
22
|
+
droppedMarks: number
|
|
23
|
+
/** Evicted or rejected metric samples; rolled-over samples are not counted. */
|
|
24
|
+
droppedMetrics: number
|
|
25
|
+
}
|