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,60 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "TraceTypes.hpp"
|
|
3
|
+
#include <deque>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include <map>
|
|
6
|
+
#include <mutex>
|
|
7
|
+
#include <optional>
|
|
8
|
+
namespace margelo::nitro::tracingcore {
|
|
9
|
+
// A native API independent of JSI; native workers may share this recorder directly.
|
|
10
|
+
class Recorder final {
|
|
11
|
+
public:
|
|
12
|
+
using Clock = std::function<double()>;
|
|
13
|
+
explicit Recorder(Config config, Clock clock = monotonicMilliseconds);
|
|
14
|
+
uint64_t startSpan(Context context, std::string parentSpanId = {});
|
|
15
|
+
std::string recordSpan(Context context, std::string parent, double start, double duration, Outcome outcome,
|
|
16
|
+
std::string sourceId = {}, std::string sourceParent = {});
|
|
17
|
+
void endSpan(uint64_t token, Outcome outcome);
|
|
18
|
+
void mark(Context context, std::optional<double> timestamp = {});
|
|
19
|
+
void metric(Context context, double value, std::string unit, std::optional<double> timestamp = {});
|
|
20
|
+
Page read(uint64_t afterSequence, size_t limit);
|
|
21
|
+
Stats stats();
|
|
22
|
+
Snapshot snapshot();
|
|
23
|
+
void stop();
|
|
24
|
+
void clear();
|
|
25
|
+
std::string spanId(uint64_t token) const;
|
|
26
|
+
size_t memorySize() const;
|
|
27
|
+
static double monotonicMilliseconds();
|
|
28
|
+
|
|
29
|
+
private:
|
|
30
|
+
struct Active {
|
|
31
|
+
double start;
|
|
32
|
+
Context context;
|
|
33
|
+
std::string parent;
|
|
34
|
+
size_t bytes;
|
|
35
|
+
};
|
|
36
|
+
Config config_;
|
|
37
|
+
Clock clock_;
|
|
38
|
+
double origin_;
|
|
39
|
+
double wallOrigin_;
|
|
40
|
+
std::string sessionId_;
|
|
41
|
+
// Protects mutable state shared by JS calls, native producers and snapshot workers.
|
|
42
|
+
mutable std::mutex mutex_;
|
|
43
|
+
std::map<uint64_t, Active> active_;
|
|
44
|
+
std::deque<Event> events_;
|
|
45
|
+
size_t bytes_ = 0;
|
|
46
|
+
size_t metrics_ = 0;
|
|
47
|
+
uint64_t token_ = 0, sequence_ = 0, dropped_ = 0;
|
|
48
|
+
uint64_t droppedSpans_ = 0, droppedMarks_ = 0, droppedMetrics_ = 0;
|
|
49
|
+
void drop(const Event &e);
|
|
50
|
+
bool recording_ = true;
|
|
51
|
+
double now() const;
|
|
52
|
+
void requireRecording() const;
|
|
53
|
+
void expire(double time);
|
|
54
|
+
void finish(std::map<uint64_t, Active>::iterator it, Outcome outcome, double time);
|
|
55
|
+
void append(Event event);
|
|
56
|
+
bool reserve(size_t bytes);
|
|
57
|
+
void evict();
|
|
58
|
+
Stats statsAt(double time) const;
|
|
59
|
+
};
|
|
60
|
+
} // namespace margelo::nitro::tracingcore
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#include "Retention.hpp"
|
|
2
|
+
#include <stdexcept>
|
|
3
|
+
namespace margelo::nitro::tracingcore {
|
|
4
|
+
void validateContext(const Context &c) {
|
|
5
|
+
if (c.name.empty() || c.name.size() > 256 || c.correlationId.size() > 256 || c.attributes.size() > 32)
|
|
6
|
+
throw std::invalid_argument("Trace name must be 1-256 bytes, correlationId <=256 bytes, attributes <=32");
|
|
7
|
+
for (const auto &a : c.attributes)
|
|
8
|
+
if (a.key.empty() || a.key.size() > 64 || a.value.size() > 1024)
|
|
9
|
+
throw std::invalid_argument("Trace attribute key must be 1-64 bytes and value <=1024 bytes");
|
|
10
|
+
}
|
|
11
|
+
size_t contextBytes(const Context &c) {
|
|
12
|
+
size_t n =
|
|
13
|
+
sizeof(Context) + c.name.capacity() + c.correlationId.capacity() + c.attributes.capacity() * sizeof(Attribute);
|
|
14
|
+
for (const auto &a : c.attributes)
|
|
15
|
+
n += a.key.capacity() + a.value.capacity();
|
|
16
|
+
return n;
|
|
17
|
+
}
|
|
18
|
+
size_t eventBytes(const Event &e) {
|
|
19
|
+
size_t n = sizeof(Event) + contextBytes(e.context);
|
|
20
|
+
if (const auto *s = std::get_if<SpanData>(&e.data))
|
|
21
|
+
n += s->spanId.capacity() + s->parentSpanId.capacity();
|
|
22
|
+
if (const auto *m = std::get_if<MetricData>(&e.data))
|
|
23
|
+
n += m->unit.capacity();
|
|
24
|
+
return n;
|
|
25
|
+
}
|
|
26
|
+
} // namespace margelo::nitro::tracingcore
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#include "TraceJson.hpp"
|
|
2
|
+
#include <algorithm>
|
|
3
|
+
#include <iomanip>
|
|
4
|
+
#include <locale>
|
|
5
|
+
#include <map>
|
|
6
|
+
#include <sstream>
|
|
7
|
+
#include <vector>
|
|
8
|
+
namespace margelo::nitro::tracingcore {
|
|
9
|
+
namespace {
|
|
10
|
+
void quote(std::ostream &o, const std::string &s) {
|
|
11
|
+
constexpr char hex[] = "0123456789abcdef";
|
|
12
|
+
o << '"';
|
|
13
|
+
for (unsigned char c : s) {
|
|
14
|
+
if (c == '"' || c == '\\')
|
|
15
|
+
o << '\\' << c;
|
|
16
|
+
else if (c < 32)
|
|
17
|
+
o << "\\u00" << hex[c >> 4] << hex[c & 15];
|
|
18
|
+
else
|
|
19
|
+
o << c;
|
|
20
|
+
}
|
|
21
|
+
o << '"';
|
|
22
|
+
}
|
|
23
|
+
const char *outcomeName(Outcome o) {
|
|
24
|
+
switch (o) {
|
|
25
|
+
case Outcome::Success:
|
|
26
|
+
return "success";
|
|
27
|
+
case Outcome::Error:
|
|
28
|
+
return "error";
|
|
29
|
+
case Outcome::Cancelled:
|
|
30
|
+
return "cancelled";
|
|
31
|
+
case Outcome::Interrupted:
|
|
32
|
+
return "interrupted";
|
|
33
|
+
}
|
|
34
|
+
return "unknown";
|
|
35
|
+
}
|
|
36
|
+
void eventJson(std::ostream &o, const Event &e) {
|
|
37
|
+
o << "{\"sequence\":" << e.sequence << ",\"timestampMs\":" << e.timestampMs << ",\"name\":";
|
|
38
|
+
quote(o, e.context.name);
|
|
39
|
+
o << ",\"correlationId\":";
|
|
40
|
+
quote(o, e.context.correlationId);
|
|
41
|
+
o << ",\"attributes\":[";
|
|
42
|
+
bool comma = false;
|
|
43
|
+
for (const auto &a : e.context.attributes) {
|
|
44
|
+
if (comma)
|
|
45
|
+
o << ',';
|
|
46
|
+
comma = true;
|
|
47
|
+
o << "{\"key\":";
|
|
48
|
+
quote(o, a.key);
|
|
49
|
+
o << ",\"value\":";
|
|
50
|
+
quote(o, a.value);
|
|
51
|
+
o << '}';
|
|
52
|
+
}
|
|
53
|
+
o << ']';
|
|
54
|
+
if (const auto *s = std::get_if<SpanData>(&e.data)) {
|
|
55
|
+
o << ",\"kind\":\"span\",\"spanId\":";
|
|
56
|
+
quote(o, s->spanId);
|
|
57
|
+
o << ",\"parentSpanId\":";
|
|
58
|
+
quote(o, s->parentSpanId);
|
|
59
|
+
o << ",\"durationMs\":" << s->durationMs << ",\"outcome\":";
|
|
60
|
+
quote(o, outcomeName(s->outcome));
|
|
61
|
+
} else if (const auto *m = std::get_if<MetricData>(&e.data)) {
|
|
62
|
+
o << ",\"kind\":\"metric\",\"value\":" << m->value << ",\"unit\":";
|
|
63
|
+
quote(o, m->unit);
|
|
64
|
+
} else
|
|
65
|
+
o << ",\"kind\":\"mark\"";
|
|
66
|
+
o << '}';
|
|
67
|
+
}
|
|
68
|
+
const std::string &sourceOf(const Event &e) {
|
|
69
|
+
static const std::string fallback = "app";
|
|
70
|
+
for (const auto &a : e.context.attributes)
|
|
71
|
+
if (a.key == "source" && !a.value.empty())
|
|
72
|
+
return a.value;
|
|
73
|
+
return fallback;
|
|
74
|
+
}
|
|
75
|
+
void argsJson(std::ostream &o, const Event &e) {
|
|
76
|
+
o << "\"args\":{\"correlationId\":";
|
|
77
|
+
quote(o, e.context.correlationId);
|
|
78
|
+
for (const auto &a : e.context.attributes) {
|
|
79
|
+
o << ',';
|
|
80
|
+
quote(o, a.key);
|
|
81
|
+
o << ':';
|
|
82
|
+
quote(o, a.value);
|
|
83
|
+
}
|
|
84
|
+
if (const auto *s = std::get_if<SpanData>(&e.data)) {
|
|
85
|
+
o << ",\"outcome\":";
|
|
86
|
+
quote(o, outcomeName(s->outcome));
|
|
87
|
+
o << ",\"spanId\":";
|
|
88
|
+
quote(o, s->spanId);
|
|
89
|
+
o << ",\"parentSpanId\":";
|
|
90
|
+
quote(o, s->parentSpanId);
|
|
91
|
+
}
|
|
92
|
+
o << '}';
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Lanes per source where spans either nest or follow each other. Perfetto requires strict
|
|
96
|
+
* nesting of complete events on one thread, so overlapping siblings get another lane.
|
|
97
|
+
*/
|
|
98
|
+
class Lanes {
|
|
99
|
+
public:
|
|
100
|
+
int place(const std::string &source, double start, double end) {
|
|
101
|
+
auto &lanes = bySource_[source];
|
|
102
|
+
for (auto &lane : lanes) {
|
|
103
|
+
while (!lane.open.empty() && lane.open.back() <= start)
|
|
104
|
+
lane.open.pop_back();
|
|
105
|
+
if (lane.open.empty() || end <= lane.open.back()) {
|
|
106
|
+
lane.open.push_back(end);
|
|
107
|
+
return lane.tid;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
lanes.push_back({next_++, {end}});
|
|
111
|
+
names_.emplace_back(lanes.back().tid, lanes.size() == 1 ? source : source + " #" + std::to_string(lanes.size()));
|
|
112
|
+
return lanes.back().tid;
|
|
113
|
+
}
|
|
114
|
+
int first(const std::string &source) {
|
|
115
|
+
auto &lanes = bySource_[source];
|
|
116
|
+
if (lanes.empty()) {
|
|
117
|
+
lanes.push_back({next_++, {}});
|
|
118
|
+
names_.emplace_back(lanes.back().tid, source);
|
|
119
|
+
}
|
|
120
|
+
return lanes.front().tid;
|
|
121
|
+
}
|
|
122
|
+
const std::vector<std::pair<int, std::string>> &names() const { return names_; }
|
|
123
|
+
|
|
124
|
+
private:
|
|
125
|
+
struct Lane {
|
|
126
|
+
int tid;
|
|
127
|
+
std::vector<double> open;
|
|
128
|
+
};
|
|
129
|
+
std::map<std::string, std::vector<Lane>> bySource_;
|
|
130
|
+
std::vector<std::pair<int, std::string>> names_;
|
|
131
|
+
int next_ = 1;
|
|
132
|
+
};
|
|
133
|
+
} // namespace
|
|
134
|
+
std::string exportTraceEvents(const Snapshot &s) {
|
|
135
|
+
std::vector<const Event *> events;
|
|
136
|
+
for (const auto &e : s.page.events)
|
|
137
|
+
events.push_back(&e);
|
|
138
|
+
const auto duration = [](const Event *e) {
|
|
139
|
+
const auto *span = std::get_if<SpanData>(&e->data);
|
|
140
|
+
return span ? span->durationMs : 0;
|
|
141
|
+
};
|
|
142
|
+
// Parents before children: earlier start first, longer span first on ties.
|
|
143
|
+
std::stable_sort(events.begin(), events.end(), [&](const Event *a, const Event *b) {
|
|
144
|
+
return a->timestampMs != b->timestampMs ? a->timestampMs < b->timestampMs : duration(a) > duration(b);
|
|
145
|
+
});
|
|
146
|
+
std::ostringstream body;
|
|
147
|
+
body.imbue(std::locale::classic());
|
|
148
|
+
body << std::setprecision(17);
|
|
149
|
+
Lanes lanes;
|
|
150
|
+
for (const auto *e : events) {
|
|
151
|
+
const auto &source = sourceOf(*e);
|
|
152
|
+
const double ts = e->timestampMs * 1000; // Trace Event timestamps are microseconds.
|
|
153
|
+
body << ",{\"pid\":1,\"name\":";
|
|
154
|
+
if (const auto *span = std::get_if<SpanData>(&e->data)) {
|
|
155
|
+
quote(body, e->context.name);
|
|
156
|
+
body << ",\"cat\":";
|
|
157
|
+
quote(body, source);
|
|
158
|
+
body << ",\"ph\":\"X\",\"ts\":" << ts << ",\"dur\":" << span->durationMs * 1000
|
|
159
|
+
<< ",\"tid\":" << lanes.place(source, e->timestampMs, e->timestampMs + span->durationMs) << ',';
|
|
160
|
+
} else if (const auto *metric = std::get_if<MetricData>(&e->data)) {
|
|
161
|
+
// Counter tracks are keyed by name, so the unit is part of it.
|
|
162
|
+
quote(body, e->context.name + " (" + metric->unit + ")");
|
|
163
|
+
body << ",\"cat\":";
|
|
164
|
+
quote(body, source);
|
|
165
|
+
body << ",\"ph\":\"C\",\"ts\":" << ts << ",\"args\":{\"value\":" << metric->value << "}}";
|
|
166
|
+
continue;
|
|
167
|
+
} else {
|
|
168
|
+
quote(body, e->context.name);
|
|
169
|
+
body << ",\"cat\":";
|
|
170
|
+
quote(body, source);
|
|
171
|
+
body << ",\"ph\":\"i\",\"s\":\"t\",\"ts\":" << ts << ",\"tid\":" << lanes.first(source) << ',';
|
|
172
|
+
}
|
|
173
|
+
argsJson(body, *e);
|
|
174
|
+
body << '}';
|
|
175
|
+
}
|
|
176
|
+
std::ostringstream o;
|
|
177
|
+
o.imbue(std::locale::classic());
|
|
178
|
+
o << std::setprecision(17);
|
|
179
|
+
o << "{\"displayTimeUnit\":\"ms\",\"otherData\":{\"generator\":\"react-native-nitro-tracing\",\"sessionId\":";
|
|
180
|
+
quote(o, s.stats.sessionId);
|
|
181
|
+
o << ",\"startedAtUnixMs\":" << s.stats.startedAtUnixMs << ",\"droppedEvents\":" << s.stats.droppedEvents
|
|
182
|
+
<< ",\"droppedSpans\":" << s.stats.droppedSpans << ",\"droppedMarks\":" << s.stats.droppedMarks
|
|
183
|
+
<< "},\"traceEvents\":[{\"pid\":1,\"ph\":\"M\",\"name\":\"process_name\",\"args\":{\"name\":\"React Native app\"}}";
|
|
184
|
+
for (const auto &[tid, name] : lanes.names()) {
|
|
185
|
+
o << ",{\"pid\":1,\"tid\":" << tid << ",\"ph\":\"M\",\"name\":\"thread_name\",\"args\":{\"name\":";
|
|
186
|
+
quote(o, name);
|
|
187
|
+
o << "}},{\"pid\":1,\"tid\":" << tid
|
|
188
|
+
<< ",\"ph\":\"M\",\"name\":\"thread_sort_index\",\"args\":{\"sort_index\":" << tid << "}}";
|
|
189
|
+
}
|
|
190
|
+
o << body.str() << "]}";
|
|
191
|
+
return o.str();
|
|
192
|
+
}
|
|
193
|
+
std::string exportJson(const Snapshot &s) {
|
|
194
|
+
std::ostringstream o;
|
|
195
|
+
o.imbue(std::locale::classic());
|
|
196
|
+
o << std::setprecision(17);
|
|
197
|
+
o << "{\"schemaVersion\":1,\"sessionId\":";
|
|
198
|
+
quote(o, s.stats.sessionId);
|
|
199
|
+
o << ",\"startedAtUnixMs\":" << s.stats.startedAtUnixMs << ",\"recording\":" << (s.stats.recording ? "true" : "false")
|
|
200
|
+
<< ",\"activeSpans\":" << s.stats.activeSpans << ",\"droppedEvents\":" << s.stats.droppedEvents
|
|
201
|
+
<< ",\"droppedSpans\":" << s.stats.droppedSpans << ",\"droppedMarks\":" << s.stats.droppedMarks
|
|
202
|
+
<< ",\"droppedMetrics\":" << s.stats.droppedMetrics << ",\"earliestSequence\":" << s.page.earliestSequence
|
|
203
|
+
<< ",\"events\":[";
|
|
204
|
+
bool comma = false;
|
|
205
|
+
for (const auto &e : s.page.events) {
|
|
206
|
+
if (comma)
|
|
207
|
+
o << ',';
|
|
208
|
+
comma = true;
|
|
209
|
+
eventJson(o, e);
|
|
210
|
+
}
|
|
211
|
+
o << "]}";
|
|
212
|
+
return o.str();
|
|
213
|
+
}
|
|
214
|
+
} // namespace margelo::nitro::tracingcore
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "TraceTypes.hpp"
|
|
3
|
+
namespace margelo::nitro::tracingcore {
|
|
4
|
+
std::string exportJson(const Snapshot &snapshot);
|
|
5
|
+
/** Chrome Trace Event JSON: opens in ui.perfetto.dev and chrome://tracing. */
|
|
6
|
+
std::string exportTraceEvents(const Snapshot &snapshot);
|
|
7
|
+
} // namespace margelo::nitro::tracingcore
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <cstdint>
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <variant>
|
|
5
|
+
#include <vector>
|
|
6
|
+
namespace margelo::nitro::tracingcore {
|
|
7
|
+
struct Attribute {
|
|
8
|
+
std::string key;
|
|
9
|
+
std::string value;
|
|
10
|
+
};
|
|
11
|
+
struct Context {
|
|
12
|
+
std::string name;
|
|
13
|
+
std::string correlationId;
|
|
14
|
+
std::vector<Attribute> attributes;
|
|
15
|
+
};
|
|
16
|
+
enum class Outcome { Success, Error, Cancelled, Interrupted };
|
|
17
|
+
struct SpanData {
|
|
18
|
+
std::string spanId;
|
|
19
|
+
std::string parentSpanId;
|
|
20
|
+
double durationMs;
|
|
21
|
+
Outcome outcome;
|
|
22
|
+
};
|
|
23
|
+
struct MarkData {};
|
|
24
|
+
struct MetricData {
|
|
25
|
+
double value;
|
|
26
|
+
std::string unit;
|
|
27
|
+
};
|
|
28
|
+
struct Event {
|
|
29
|
+
uint64_t sequence;
|
|
30
|
+
double timestampMs;
|
|
31
|
+
Context context;
|
|
32
|
+
std::variant<SpanData, MarkData, MetricData> data;
|
|
33
|
+
};
|
|
34
|
+
struct Config {
|
|
35
|
+
size_t maxEvents;
|
|
36
|
+
size_t maxBytes;
|
|
37
|
+
size_t maxActiveSpans;
|
|
38
|
+
double spanTimeoutMs;
|
|
39
|
+
};
|
|
40
|
+
struct Stats {
|
|
41
|
+
std::string sessionId;
|
|
42
|
+
double startedAtUnixMs;
|
|
43
|
+
double nowMs;
|
|
44
|
+
bool recording;
|
|
45
|
+
size_t eventCount;
|
|
46
|
+
size_t retainedBytes;
|
|
47
|
+
uint64_t droppedEvents;
|
|
48
|
+
size_t activeSpans;
|
|
49
|
+
/** droppedEvents by kind, so a UI can say what history is missing. */
|
|
50
|
+
uint64_t droppedSpans = 0, droppedMarks = 0, droppedMetrics = 0;
|
|
51
|
+
};
|
|
52
|
+
struct Page {
|
|
53
|
+
std::vector<Event> events;
|
|
54
|
+
uint64_t nextSequence;
|
|
55
|
+
uint64_t earliestSequence;
|
|
56
|
+
uint64_t droppedEvents;
|
|
57
|
+
};
|
|
58
|
+
struct Snapshot {
|
|
59
|
+
Stats stats;
|
|
60
|
+
Page page;
|
|
61
|
+
};
|
|
62
|
+
} // namespace margelo::nitro::tracingcore
|
package/expo.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#import <QuartzCore/QuartzCore.h>
|
|
2
|
+
#import <UIKit/UIKit.h>
|
|
3
|
+
#include "../cpp/core/NativeSampler.hpp"
|
|
4
|
+
|
|
5
|
+
using margelo::nitro::tracingcore::FrameMonitor;
|
|
6
|
+
|
|
7
|
+
/// Main run loop display callbacks. A callback delayed past its vsync means the main thread
|
|
8
|
+
/// was busy; FrameMonitor turns those gaps into slow and frozen frame counts.
|
|
9
|
+
@interface NitroTracingFrameSource : NSObject
|
|
10
|
+
@property(nonatomic, strong) CADisplayLink *link;
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
@implementation NitroTracingFrameSource
|
|
14
|
+
- (void)tick:(CADisplayLink *)link {
|
|
15
|
+
// targetTimestamp - timestamp is the current frame interval, including ProMotion rates.
|
|
16
|
+
FrameMonitor::instance().onFrame(link.timestamp, link.targetTimestamp - link.timestamp);
|
|
17
|
+
}
|
|
18
|
+
@end
|
|
19
|
+
|
|
20
|
+
static NitroTracingFrameSource *source;
|
|
21
|
+
|
|
22
|
+
__attribute__((constructor)) static void NitroTracingRegisterFrameSource() {
|
|
23
|
+
FrameMonitor::instance().setToggle([](bool enabled) {
|
|
24
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
25
|
+
if (enabled && !source) {
|
|
26
|
+
source = [NitroTracingFrameSource new];
|
|
27
|
+
source.link = [CADisplayLink displayLinkWithTarget:source selector:@selector(tick:)];
|
|
28
|
+
[source.link addToRunLoop:NSRunLoop.mainRunLoop forMode:NSRunLoopCommonModes];
|
|
29
|
+
} else if (!enabled && source) {
|
|
30
|
+
[source.link invalidate];
|
|
31
|
+
source = nil;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|