Trace allows you to add custom trace events to your code, helping you track specific operations or logic flows. This is useful for profiling custom business logic, measuring durations, or marking important points in your app.
useEffect
hook takes;By adding custom trace events, you transform opaque code sections into visible, measurable segments in Trace’s timeline, enabling precise performance tuning.
// Basic usage
- (void)measure {
[LynxTraceEvent beginSection:@"render" withName:@"measure"]; // 'measure' slice start
// ... your code ...
[LynxTraceEvent endSection:@"render" withName:@"measure"]; // 'measure' slice end
}
// With custom arguments
- (void)draw {
[LynxTraceEvent beginSection:@"render" withName:@"draw-image" debugInfo:@{@"component": @"Image", @"size": @"large"}];
// ... your code ...
[LynxTraceEvent endSection:@"render" withName:@"draw-image"];
}
// Basic usage
- (void)requestBegin {
// ...
[LynxTraceEvent instant:@"network" withName:@"request-begin"];
// ...
}
// With custom arguments
- (void)requestFinished {
// ...
[LynxTraceEvent instant:@"network" withName:@"request-finished" debugInfo:@{@"url": @"https://example.com", @"method": @"GET"}];
// ...
}
beginSection
must have a corresponding endSection
, and both calls must occur on the same thread.endSection
from being called.// Exception causes endSection not to be called
- (void)measureWithError:(BOOL)shouldThrow {
[LynxTraceEvent beginSection:@"measure"];
// ...
@throw [NSException exceptionWithName:@"TestException" reason:@"Error occurred" userInfo:nil];
// endSection will not be called due to exception
[LynxTraceEvent endSection:@"measure"];
}
// Early return causes endSection not to be called
- (void)measureWithFastExit:(BOOL)fastExit {
[LynxTraceEvent beginSection:@"measure"];
// Early return, endSection not called
if (fastExit) return;
// ...
[LynxTraceEvent endSection:@"measure"];
}
// Cross-thread begin/end mismatch
[LynxTraceEvent beginSection:@"background-task"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// ...
[LynxTraceEvent endSection:@"background-task"]; // Error: not same thread
});
- (void)measureWithError:(BOOL)shouldThrow {
@try {
[LynxTraceEvent beginSection:@"measure"];
// ...
@throw [NSException exceptionWithName:@"TestException" reason:@"Error occurred" userInfo:nil];
}
@finally {
// Exception safe: ensure endSection is always called
[LynxTraceEvent endSection:@"measure"];
}
}
- (void)measureWithFastExit:(BOOL)fastExit {
[LynxTraceEvent beginSection:@"measure"];
if (fastExit) {
// Early return safe
[LynxTraceEvent endSection:@"measure"];
return;
}
// ...
[LynxTraceEvent endSection:@"measure"];
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Thread safe: begin/end on the same thread
[LynxTraceEvent beginSection:@"background-task"];
// ...
[LynxTraceEvent endSection:@"background-task"];
});
beginSection
/endSection
across asynchronous boundaries like timers or callbacks.// Timer/callback
[LynxTraceEvent beginSection:@"async-function"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, time), dispatch_get_main_queue(), ^{
// ...
[LynxTraceEvent endSection:@"async-function"];
});
// Async task
[LynxTraceEvent beginSection:@"await-task"];
[someAsyncFunction waitUntilFinished];
[LynxTraceEvent endSection:@"await-task"];
// Timer/callback: use begin/end inside callback
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, time), dispatch_get_main_queue(), ^{
[LynxTraceEvent beginSection:@"async-function"];
// ...
[LynxTraceEvent endSection:@"async-function"];
});
// Async task: use instant events
[LynxTraceEvent instant:@"async-task" withName:@"start"];
[someAsyncFunction waitUntilFinished];
[LynxTraceEvent instant:@"async-task" withName:@"end"];
// Basic usage
void measure() {
TraceEvent.beginSection("render", "measure");
// ... your code ...
TraceEvent.endSection("render", "measure");
}
// With custom arguments
void draw() {
Map<String, String> args = new HashMap<>();
args.put("component", "Image");
args.put("size", "large");
TraceEvent.beginSection("render", "draw-image", args);
// ... your code ...
TraceEvent.endSection("render", "draw-image");
}
// Basic usage
void requestBegin() {
// ...
TraceEvent.instant("network", "request-begin");
// ...
}
// With custom arguments
void requestFinished() {
// ...
Map<String, String> args = new HashMap<>();
args.put("url", "https://example.com");
args.put("method", "GET");
TraceEvent.instant("network", "request-finished", args);
//...
}
beginSection
must have a corresponding endSection
, and both calls must occur on the same thread.endSection
from being called.public void measure() throws Exception {
TraceEvent.beginSection("measure");
// ...
exceptionFunction(); // May throw exception
// endSection not called due to exception
TraceEvent.endSection("measure");
}
public void measure(boolean fastExit) {
TraceEvent.beginSection("measure");
// Early return causes endSection not to be called
if (fastExit) return;
// ...
TraceEvent.endSection("measure");
}
// Cross-thread: begin/end not in the same thread
TraceEvent.beginSection("background-task");
new Thread(() -> {
// ...
TraceEvent.endSection("background-task");
}).start();
public void measure() throws Exception {
try {
TraceEvent.beginSection("measure");
// ...
exceptionFunction();
} finally {
// Exception safe
TraceEvent.endSection("measure");
}
}
public void measure() {
TraceEvent.beginSection("measure");
if (fastExit) {
// Early return safe
TraceEvent.endSection("measure");
return;
}
// ...
TraceEvent.endSection("measure");
}
new Thread(() -> {
// Thread safe: begin/end in the same thread
TraceEvent.beginSection("background-task");
// ...
TraceEvent.endSection("background-task");
}).start();
beginSection
/endSection
across asynchronous boundaries like timers or callbacks.// Timer/callback
TraceEvent.beginSection("async-function");
new Handler().postDelayed(() -> {
// ...
TraceEvent.endSection("async-function");
}, 3000);
// Async task
TraceEvent.beginSection("await-task");
someAsyncFunction().get(); // Assume this is async wait
TraceEvent.endSection("await-task");
// Timer/callback: use begin/end inside callback
new Handler().postDelayed(() -> {
TraceEvent.beginSection("async-function");
// ...
TraceEvent.endSection("async-function");
}, 3000);
// Async task: use instant events
TraceEvent.instant("async-task", "async-task-start");
someAsyncFunction().get();
TraceEvent.instant("async-task", "async-task-end");
// Basic usage
function measure() {
TraceEvent.beginSection(TraceCategory.Other, "measure");
// ... your code ...
TraceEvent.endSection(TraceCategory.Other, "measure");
}
// With custom arguments
function draw() {
const args: Record<string, string> = {
"component": "Image",
"size": "large"
}
TraceEvent.beginSection(TraceCategory.Other, "draw-image", args);
// ... your code ...
TraceEvent.endSection(TraceCategory.Other, "draw-image");
}
// Basic usage
function requestBegin() {
// ...
TraceEvent.instant(TraceCategory.Other, "request-begin")
// ...
}
// With custom arguments
function requestFinished() {
// ...
const args: Record<string, string> = {
"url": "https://example.com",
"method": "GET"
}
TraceEvent.instant(TraceCategory.Other, "request-finished", args);
//...
}
beginSection
must have a corresponding endSection
, and both calls must occur on the same thread.endSection
from being called.function measure() {
TraceEvent.beginSection(TraceCategory.Other, 'measure');
// ...
throw new Error('Error occurred');
// profileEnd not called due to exception
TraceEvent.endSection(TraceCategory.Other, 'measure');
}
function measureWithFastExit(fastExit) {
TraceEvent.beginSection(TraceCategory.Other, 'measure');
// Early return causes profileEnd not to be called
if (fastExit) return;
// ...
TraceEvent.endSection(TraceCategory.Other, 'measure');
}
// Cross-async/thread begin/end mismatch
TraceEvent.beginSection(TraceCategory.Other, 'background-task');
setTimeout(() => {
// ...
TraceEvent.endSection(TraceCategory.Other, 'background-task');
}, 1000);
function measure(shouldThrow) {
try {
TraceEvent.beginSection(TraceCategory.Other, 'measure');
// ...
throw new Error('Error occurred');
} finally {
// Exception safe: ensure profileEnd is always called
TraceEvent.endSection(TraceCategory.Other, 'measure');
}
}
function measureWithFastExit(fastExit) {
TraceEvent.beginSection(TraceCategory.Other, 'measure');
if (fastExit) {
// Early return safe
TraceEvent.endSection(TraceCategory.Other, 'measure');
return;
}
// ...
TraceEvent.endSection(TraceCategory.Other, 'measure');
}
setTimeout(() => {
// Thread safe: begin/end in the same execution context
TraceEvent.beginSection(TraceCategory.Other, 'background-task');
// ...
TraceEvent.endSection(TraceCategory.Other, 'background-task');
}, 0);
beginSection
/endSection
across asynchronous boundaries such as timers, callbacks, or await
/Promise
.// Timer/callback
TraceEvent.beginSection(TraceCategory.Other, 'async function');
setTimeout(() => {
// ...
TraceEvent.endSection(TraceCategory.Other, 'async function');
}, 3000);
// await/promise
TraceEvent.beginSection(TraceCategory.Other, 'await-task');
await someAsyncFunc();
TraceEvent.endSection(TraceCategory.Other, 'await-task');
// Timer/callback: use begin/end inside the callback
setTimeout(() => {
TraceEvent.beginSection(TraceCategory.Other, 'async function');
// ...
TraceEvent.endSection(TraceCategory.Other, 'async function');
}, 3000);
// await/promise: use instant trace events
TraceEvent.instant(TraceCategory.Other, 'await-task:begin');
await someAsyncFunc();
TraceEvent.instant(TraceCategory.Other, 'await-task:end');
// Basic usage
function handleClick() {
lynx.performance.profileStart('handle-click');
// ... your code ...
lynx.performance.profileEnd();
}
// With custom arguments
useEffect(() => {
lynx.performance.profileStart('useEffect', {
args: { count },
});
// ... your code ...
lynx.performance.profileEnd();
}, [count]);
function fetchData() {
// Basic usage
lynx.performance.profileMark('fetch-data-begin');
fetch(url).then((res) => {
// With custom arguments
lynx.performance.profileMark('fetch-data-end', {
args: { url: 'https://example.com', method: 'GET' },
});
});
}
const flowId = lynx.performance.profileFlowId();
lynx.performance.profileMark('user-action-begin', { flowId });
// ...later, in an async callback
setTimeout(() => {
// ...
lynx.performance.profileMark('user-action-end', { flowId });
}, 1000);
profileStart
must have a corresponding profileEnd
, and both calls must occur on the same thread.profileEnd
from being called.function measure() {
lynx.performance.profileStart('measure');
// ...
throw new Error('Error occurred');
// profileEnd not called due to exception
lynx.performance.profileEnd();
}
function measureWithFastExit(fastExit) {
lynx.performance.profileStart('measure');
// Early return causes profileEnd not to be called
if (fastExit) return;
// ...
lynx.performance.profileEnd();
}
// Cross-async/thread begin/end mismatch
lynx.performance.profileStart('background-task');
setTimeout(() => {
// ...
lynx.performance.profileEnd();
}, 1000);
function measure(shouldThrow) {
try {
lynx.performance.profileStart('measure');
// ...
throw new Error('Error occurred');
} finally {
// Exception safe: ensure profileEnd is always called
lynx.performance.profileEnd();
}
}
function measureWithFastExit(fastExit) {
lynx.performance.profileStart('measure');
if (fastExit) {
// Early return safe
lynx.performance.profileEnd();
return;
}
// ...
lynx.performance.profileEnd();
}
setTimeout(() => {
// Thread safe: begin/end in the same execution context
lynx.performance.profileStart('background-task');
// ...
lynx.performance.profileEnd();
}, 0);
profileStart
/profileEnd
across asynchronous boundaries such as timers, callbacks, or await
/Promise
.// Timer/callback
lynx.performance.profileStart('async function');
setTimeout(() => {
// ...
lynx.performance.profileEnd();
}, 3000);
// await/promise
lynx.performance.profileStart('await-task');
await someAsyncFunc();
lynx.performance.profileEnd();
// Timer/callback: use begin/end inside the callback
setTimeout(() => {
lynx.performance.profileStart('async function');
// ...
lynx.performance.profileEnd();
}, 3000);
// await/promise: use instant trace events
lynx.performance.profileMark('async-task:start');
await someAsyncFunc();
lynx.performance.profileMark('async-task:end');