# Manual spans


The browser client automatically times page loads, navigations, and HTTP requests. It can't time your own code for you, for example a slow client side calculation. For that, wrap the code in a manual span.

A manual span automatically becomes a child of whatever span is currently active, for example the current page load. You don't need to pass a parent yourself.

## withSpan

`withSpan` wraps a function, times it, and ends the span for you when the function returns:

```js
import { flare } from '@flareapp/js';

function generateInvoiceReport(rows) {
    return flare.withSpan('generate-invoice-report', () => {
        return rows
            .filter((row) => row.status === 'paid')
            .map((row) => calculateRowTotals(row))
            .sort((a, b) => b.total - a.total);
    });
}
```

If the function returns a promise, `withSpan` waits for it and ends the span once the promise settles. If the function throws or its promise rejects, the span is marked as an error before it ends. Either way, you never call `end()` yourself.

## startSpan and span.end()

Use `startSpan` when the work you're timing doesn't fit inside a single function call, for example when it spans multiple event handlers. Call `end()` on the span yourself once the work is done:

```js
import { flare } from '@flareapp/js';

function generateInvoiceReport(rows) {
    const span = flare.startSpan('generate-invoice-report');

    const result = rows
        .filter((row) => row.status === 'paid')
        .map((row) => calculateRowTotals(row))
        .sort((a, b) => b.total - a.total);

    span.end();

    return result;
}
```

Unlike `withSpan`, `startSpan` does not end the span or set an error status for you. If the code between `startSpan` and `end()` throws, make sure `end()` still runs, for example in a `finally` block.

## If tracing is off

`startSpan` and `withSpan` work even when `enableTracing` is `false`. They still create a span, and your code still runs, so you don't need to manually check whether tracing is on before calling `startSpan` or `withSpan`. The span just isn't recorded or sent to Flare.
