Skip to content

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”
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.error(error, labels?, context?, attachments?)
logger.warning(message, labels?, context?, attachments?)
logger.info(message, labels?, context?, attachments?)
// suppressed in production
logger.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.

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.

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.

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.
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.

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.

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.

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