Browser API
The browser side is split into entry points, so an app ships only what it imports. This page lists each export with its options.
@dasasian/firebase-structured-logger/client
Section titled “@dasasian/firebase-structured-logger/client”initLogger
Section titled “initLogger”import { initLogger } from '@dasasian/firebase-structured-logger/client'import { httpsCallable } from 'firebase/functions'import { functions } from './config/firebase'
export const logger = initLogger({ appId: 'my-app', releaseId: import.meta.env.VITE_RELEASE_ID ?? 'dev', logFunction: httpsCallable(functions, 'logFrontendEvent'),})Creates the session’s logger. Call it once, at the app entry, before any logging.
| Option | Meaning |
|---|---|
appId |
Required. The app name. Written to every entry as labels.appId. |
releaseId |
Required. The build. Written to every entry and used to find that build’s source maps. |
logFunction |
Required. How an entry gets to your backend: a callable, or any (payload) => Promise. |
minSeverity |
Floor for what leaves the browser. WARNING in production, DEBUG in dev. |
rateLimitOptions |
The rate-limit settings below. |
initLogger is generic over your own label type: initLogger<MyAppLabels>(...). Declare that type as a type, not an interface, or tsc rejects it.
Logger methods
Section titled “Logger methods”logger.error(error, labels?, context?, attachments?)logger.warning(message, labels?, context?, attachments?)logger.info(message, labels?, context?, attachments?)// suppressed in productionlogger.debug(message, labels?, context?, attachments?)
logger.setUser(uid, extraLabels?)logger.clearUser()logger.addBreadcrumb(type, name, data?)logger.sendFeedback(text, extras?)attachments is Record<string, Blob | File | string>. Logger is exported as a type only. The client logger is a session singleton, so annotate with Logger<MyAppLabels> and construct with initLogger(). A second instance would share breadcrumbs, screen and the rate-limit budget, and it would look independent.
getClientLogger
Section titled “getClientLogger”import { getClientLogger } from '@dasasian/firebase-structured-logger/client'
const logger = getClientLogger<MyAppLabels>()Returns the logger that initLogger created, for code that cannot import the module that holds it.
sendFeedback
Section titled “sendFeedback”import { sendFeedback } from '@dasasian/firebase-structured-logger/client'
sendFeedback('The total is wrong', { labels: { orderId: '1042' }, attachments: { photo: blob } })Sends a user report. Feedback is exempt from the rate limits and the severity floor. Options are FeedbackOptions: labels and attachments. See User feedback.
sendTestLog
Section titled “sendTestLog”import { sendTestLog } from '@dasasian/firebase-structured-logger/client'
sendTestLog()Sends one error, one warning and one info, with labels.errorType="fsl-verify". triggerTestLog is its old name.
setupGlobalErrorHandler, handleReactError, handleVueError
Section titled “setupGlobalErrorHandler, handleReactError, handleVueError”import { setupGlobalErrorHandler, handleReactError, handleVueError,} from '@dasasian/firebase-structured-logger/client'
setupGlobalErrorHandler()| Export | Use |
|---|---|
setupGlobalErrorHandler() |
Uncaught errors and unhandled rejections from window. |
handleReactError(error, errorInfo) |
onCaughtError on React 19’s createRoot, or componentDidCatch of a class boundary. See React. |
handleVueError(error, instance, info) |
app.config.errorHandler. See Vue. |
addBreadcrumb and bc
Section titled “addBreadcrumb and bc”import { addBreadcrumb, bc } from '@dasasian/firebase-structured-logger/client'
bc.action('add-to-cart', { sku: 'A12' })bc.state('cart-open')bc.handledError('payment-declined')addBreadcrumb(type, name, data?) takes a type of action, state, nav or error. The bc helper has action, state and handledError, each (name, data?). The trail keeps the last 50. See Breadcrumbs.
Rate limits
Section titled “Rate limits”import { initLogger } from '@dasasian/firebase-structured-logger/client'
initLogger({ appId: 'my-app', releaseId: 'dev', logFunction: async (payload) => { await fetch('/log', { method: 'POST', body: JSON.stringify(payload) }) }, rateLimitOptions: { burstLimit: 50, rechargeSecondsPerLog: 60, reservedForErrors: 10, duplicateLimit: 3, summaryIntervalMinutes: 60, summaryMaxAgeDays: 7, maxPendingSummaries: 50, },})| Option | Default | Meaning |
|---|---|---|
burstLimit |
50 | How many logs can go at once. |
rechargeSecondsPerLog |
60 | After a burst, seconds before one more log recharges. |
reservedForErrors |
10 | Of the burst, how many only ERROR and above may use. Capped at half of burstLimit. |
duplicateLimit |
3 | Full copies of one error before it is only counted. |
summaryIntervalMinutes |
60 | How often a running count of repeats is sent. |
summaryMaxAgeDays |
7 | How long an unsent summary waits before it is deleted. |
maxPendingSummaries |
50 | Most pending summaries kept. The oldest go first. |
See Rate limits and missing logs.
Logger, InitLoggerConfig, FeedbackOptions, RateLimitConfig, LogSeverity ('ERROR' | 'WARNING' | 'NOTICE' | 'INFO' | 'DEBUG'), LogPayload, BreadcrumbEntry and BaseLabels.
@dasasian/firebase-structured-logger/client/navigation
Section titled “@dasasian/firebase-structured-logger/client/navigation”import { enableNavigation, navigatedTo, defaultLabelsFor } from '@dasasian/firebase-structured-logger/client/navigation'
enableNavigation()navigatedTo('checkout', { route: '/checkout', path: '/checkout' })| Export | Use |
|---|---|
enableNavigation({ labelsFor? }) |
Follows URL changes and sets route, screen and path on every entry. labelsFor(path) returns { route?, screen?, path? } and its answer is final. |
navigatedTo(screen, { route?, path? }) |
A page change with no URL change. |
defaultLabelsFor(path) |
The default mapping from a path to labels. |
See Breadcrumbs.
Router adapters
Section titled “Router adapters”import { enableVueRouterNavigation } from '@dasasian/firebase-structured-logger/client/navigation/vue-router'import { enableReactRouterNavigation } from '@dasasian/firebase-structured-logger/client/navigation/react-router'
const stop = enableVueRouterNavigation(router, { adjust: (labels) => labels })enableReactRouterNavigation(router, { adjust? }) is the same for a React Router data router. Both return a function that stops listening. adjust receives the labels the adapter derived and returns the ones to use.
@dasasian/firebase-structured-logger/client/views
Section titled “@dasasian/firebase-structured-logger/client/views”import { enableViews } from '@dasasian/firebase-structured-logger/client/views'
enableViews()Records which view was on screen when an entry was written. See Tabs and dialogs.
@dasasian/firebase-structured-logger/client/timing
Section titled “@dasasian/firebase-structured-logger/client/timing”import { trace, startTrace, configureTraces } from '@dasasian/firebase-structured-logger/client/timing'
configureTraces({ app_boot: { warnAfterMs: 5000, steps: { products: 3000 } } })
await trace('app_boot', async (t) => { await t.step('products', loadProducts)})| Export | Use |
|---|---|
configureTraces({ name: { warnAfterMs?, steps? } }) |
Limits per trace name. steps maps a step name to its limit in milliseconds. |
trace(name, fn) |
Runs fn(t) and ends the trace when it finishes. |
startTrace(name) |
Returns a trace you end yourself with .end(). |
A trace is reported only when a limit is crossed. A Trace has step(name, fn) and end(). See Slow screens.
@dasasian/firebase-structured-logger/testing
Section titled “@dasasian/firebase-structured-logger/testing”import { captureEntries, resetSession } from '@dasasian/firebase-structured-logger/testing'captureEntries() returns { logFunction, entries, clear(), settled() }, and resetSession() starts a fresh session: trail, page, budget and repeat counts. See Test your logs.
Renamed and deprecated
Section titled “Renamed and deprecated”Each old name still works in 1.x with a one-time console warning, and is removed in 2.0.
| Old | New |
|---|---|
minLogLevel |
minSeverity |
rateLimitOptions.sessionLimit |
rateLimitOptions.burstLimit |
rateLimitOptions.refillPerMinute |
rateLimitOptions.rechargeSecondsPerLog, in seconds: 60 / refillPerMinute |
rateLimitOptions.errorReserve, a share |
rateLimitOptions.reservedForErrors, a count: errorReserve × burstLimit |
triggerTestLog() |
sendTestLog() |
enableNavigation({ routeFor }), ({ cleanPath }), ({ path: false }) |
enableNavigation({ labelsFor }) |
bc.nav(screen), logger.setScreen(screen) |
enableNavigation(), or navigatedTo(screen) without URL routing |
bc.error(type, data?) |
bc.handledError(type, data?), only for errors you handled and did not log |
label routeSource |
none |
Made by Dasasian