Stopwatch is the profiling utility in the package. It measures elapsed time and, in Node.js, can also capture CPU and heap deltas.
Use it when you want timing checkpoints, lap measurements, or end-of-run metrics around a block of work.
Create a stopwatch with Stopwatch.start(level, label).
import { Logger, Stopwatch } from '@samatawy/rules';
Logger.setLogLevel('info');
const timer = Stopwatch.start('info', 'Workspace.process')
.useLogger(Logger);
timer.logCheckpoint('Context loaded');
// do some work
timer.logLap('Rules evaluated');
// do more work
timer.logEnd('Workspace.process complete', { workspace: 'pricing' });
timer.logMetrics();
Stopwatch supports methods that return measurements:
checkpoint() to capture cumulative progress without resetting timinglap() to capture a segment and restart measurement from that pointend() to finish the measurement and return the final point without logging itmetrics() to compute aggregate metrics programmatically.. and methods that also log measurements before returning.
logLap() to capture a lap and emit its message through the loggerlogCheckpoint() to capture a checkpoint and emit its message through the loggerlogEnd() to finish the measurement and emit the final point through the loggerlogMetrics() to emit aggregate metrics through the configured loggerIn Node.js, stopwatch points can include:
In browser runtimes, stopwatch data falls back to timing-only measurements.
If you want custom stopwatch message output, provide a MessageFormatter.
import { Logger, MessageFormatter, Stopwatch } from '@samatawy/rules';
const timer = Stopwatch.start('debug', 'Import job')
.useLogger(Logger)
.useFormatter(
MessageFormatter.using('{label}:[? {duration} ms][? - heap {heap_delta} b]')
);
timer.logEnd();
MessageFormatter formats a plain data object. In stopwatch usage, that object typically contains stopwatch fields such as the label and timing metrics.
MessageFormatter replaces placeholders in the form {key} using values from the supplied data object.
For stopwatch messages, the commonly available placeholders are:
{label} for the stopwatch label or the label passed to the current checkpoint, lap, or end call{duration} for the measured duration{cpu_user} for user CPU time when running in Node.js{cpu_system} for system CPU time when running in Node.js{heap_delta} for heap change when running in Node.jsYou can also use any other keys if you call the formatter directly with your own data object.
MessageFormatter also supports optional blocks in the form [? ... ].
An optional block is included only if every placeholder inside that block has a defined value.
For example, this template:
const formatter = MessageFormatter.using(
'{label}[? took {duration} ms][? | heap {heap_delta} b]'
);
behaves like this:
duration and heap_delta are both defined, the full message can be included.heap_delta is not available.Example template:
const formatter = MessageFormatter.using(
'{label}[? took {duration} ms][? with cpu {cpu_user} us][? and heap {heap_delta} b]'
);
Example output in Node.js:
Import job took 14.231 ms with cpu 820 us and heap 4,096 b
Example output in a browser-like runtime:
Import job took 14.231 ms
true or falseDate values are rendered as ISO stringsmetrics() returns aggregate information derived from the checkpoints, laps, and the final stretch.
Typical fields include (when supported):
total_durationtotal_cpu_usertotal_cpu_systempeak_heap_usagecheckpoint_countfastest_lapslowest_lapaverage_laplapscheckpointsfinish_lineUse metrics() when you want to inspect or assert on performance data programmatically.
Use logMetrics() when you want to write those metrics through the configured logger.
useLogger(...) before logCheckpoint(), logLap(), logEnd(), or logMetrics() if you want explicit logger routingend() when you only need the final data object and do not want to emit a log line yet