Skip to content

Backend API

The backend entry point writes structured entries and receives the browser’s. This page lists each export with its options.

@dasasian/firebase-structured-logger/functions

Section titled “@dasasian/firebase-structured-logger/functions”
import { initLogger } from '@dasasian/firebase-structured-logger/functions'
initLogger({ appId: 'my-app', logLocalDir: '../.fsl-logs', minSeverity: 'INFO' })

Call it once, at module load.

Option Default Meaning
appId none The app name. Written to every entry.
logLocalDir none Directory for local log files, used when running in the emulator.
minSeverity WARNING in production, DEBUG in the emulator Floor for what is written. Entries below it are dropped silently.
logMaxRecordsPerFile 2000 Records per local file before rotation.
logMaxRotatedFiles 5 Rotated local files to keep.
import { onCall } from 'firebase-functions/v2/https'
import { withLogging, getLogger } from '@dasasian/firebase-structured-logger/functions'
export const placeOrder = onCall(
withLogging({ functionName: 'placeOrder' }, async (request) => {
getLogger().info('order placed', { orderId: '1042' })
return { ok: true }
}),
)

withLogging(options | (request) => options, handler) wraps a handler so its entries have the function name, the trace and the verified request.auth.uid. The options are functionName?, appId? and labels?. Passing a function lets the options depend on the request. Inside onSchedule or onTaskDispatched, name the event type as the second type argument, such as withLogging<AppLabels, ScheduledEvent>, or tsc rejects the handler. A schedule has no auth, so it has no userId. Declare the label type as a type, not an interface, or tsc rejects it.

getLogger() returns the current request’s writer, or an anonymous fallback outside a request.

import { logError, logWarn, logInfo, logDebug } from '@dasasian/firebase-structured-logger/functions'
logInfo('cache warmed', { region: 'eu' })

Each takes (message, labels?, context?, attachments?). logError takes the error as its first argument. attachments is Record<string, string | Buffer>. They write the same entries outside Cloud Functions, so they work on Cloud Run too.

import { configureAttachments } from '@dasasian/firebase-structured-logger/functions'
configureAttachments({ bucket: 'my-app.firebasestorage.app', prefix: 'logAttachments' })

Names the bucket and prefix for attachments. Call it once, at module load. See Screenshots and files.

import { configureTraces, trace } from '@dasasian/firebase-structured-logger/functions'
configureTraces({ nightly_sync: { warnAfterMs: 60000, steps: { fetch: 20000 } } })
await trace('nightly_sync', async (t) => {
await t.step('fetch', fetchRows)
})

Same shape as the browser’s. trace(name, fn) runs fn(t), and startTrace(name) returns a trace you end with .end(). A step is judged when it finishes. See Slow screens.

import { createClientLogFunction } from '@dasasian/firebase-structured-logger/functions'
export const logFrontendEvent = createClientLogFunction({
bucket: 'my-app.firebasestorage.app',
cors: true,
maxInstances: 5,
})

A ready-to-export callable that receives browser entries. maxInstances is 1 by default, a deliberate cost guard.

import { createHttpLogHandler } from '@dasasian/firebase-structured-logger/functions'
export const logHandler = createHttpLogHandler({
authorize: async (req) => Boolean(req.headers.authorization),
allowOrigin: 'https://my-app.web.app',
})

An (req, res) handler for Express and similar. authorize is required: a function returning a boolean, or 'unauthenticated' when something in front of it already did the work. A gate that throws counts as a rejection. allowOrigin defaults to *. Body parsing is yours: mount express.json() first. In Express, mount the handler with app.all, so it also receives the OPTIONS request a browser sends first. Responses: 204 written (also for a CORS OPTIONS preflight), 400 malformed payload, 401 gate refused, 405 not a POST, 500 anything else. See Cloud Run.

import { createClientLogHandler, ClientLogError } from '@dasasian/firebase-structured-logger/functions'
const handle = createClientLogHandler({ bucket: 'my-app.firebasestorage.app' })

The bare handler, for wrapping in something of your own. It takes { data: LogPayload } and throws ClientLogError, whose code is 'invalid-argument' or 'internal'.

All three handlers take the same configuration:

Option Meaning
bucket The bucket for source maps and attachments. Defaults to the Firebase default bucket.
sourceMaps.bucket A separate bucket for the maps.
sourceMaps.prefix The prefix the maps were uploaded under. Must match fsl upload-sourcemaps --prefix.

createClientLogFunction also takes cors and maxInstances, and createHttpLogHandler takes authorize and allowOrigin, as listed above. The old bucketName is bucket.

LogWriter, Trace, TraceConfig, TraceLimits, ClientLogHandlerConfig, LogRequest, HttpLogHandlerConfig, HttpLogRequest, HttpLogResponse, LogSeverity, LogPayload and BaseLabels. ClientLogRequest is the old name of LogRequest.

Made by Dasasian