FlareLog SDK - Advanced Features
Deep-dive into FlareLog's advanced capabilities: breadcrumbs, PII scrubbing, child loggers, sampling, beforeSend hooks, custom spans, and multi-backend fan-out. These features work identically across all runtimes (Node, Workers, Edge, browser).
Just getting started? See Installation first — this guide assumes you already have a working logger.
Breadcrumbs
Breadcrumbs track events leading up to an error, providing context for debugging.
import { FlareLog } from "@flarelog/sdk";
const logger = new FlareLog({
apiKey: "fl_your_api_key",
});
// Add breadcrumbs manually
logger.addBreadcrumb({
category: "navigation",
message: "User navigated to checkout",
data: { from: "/cart", to: "/checkout" },
});
logger.addBreadcrumb({
category: "ui.click",
message: "Clicked pay button",
data: { button: "pay-now", amount: 99.99 },
});
logger.addBreadcrumb({
category: "http",
message: "POST /api/payment",
data: { status: 200, durationMs: 150 },
});
// When an error occurs, last 50 breadcrumbs are included
logger.logError(new Error("Payment failed"));
// Metadata will include: { breadcrumbs: [...], error: {...} }Auto-Captured Breadcrumbs
WARNING
autoCapture.http, autoCapture.navigation, and autoCapture.clicks are not yet implemented. The options are accepted by the type system but have no effect at runtime. Use manual addBreadcrumb() calls in the meantime. console, globalErrors, and rejections capture work as expected.
The following auto-capture options are fully implemented:
const logger = new FlareLog({
autoCapture: {
console: true, // intercept console.error / console.warn
globalErrors: true, // window.onerror / process uncaughtException
rejections: true, // unhandledrejection
},
});User Context
Identify affected users for faster debugging and support.
// Set user on login
logger.setUser({
id: "user_123",
email: "user@example.com",
name: "John Doe",
plan: "premium", // custom fields
});
// Clear user on logout
logger.setUser(null);
// User context is automatically included in all logs
logger.info("Action performed");
// Metadata: { user: { id: "user_123", email: "user@example.com" } }Tags
Add searchable tags for filtering and grouping logs.
// Set tags
logger.setTag("version", "1.2.3");
logger.setTag("environment", "production");
logger.setTag("feature_flag", "new_checkout");
// Tags are included in all logs
logger.info("Event");
// Metadata: { tags: { version: "1.2.3", environment: "production" } }BeforeSend Hook
Modify or drop logs before sending. Perfect for PII scrubbing.
const logger = new FlareLog({
beforeSend: (log) => {
// Scrub sensitive fields
if (log.metadata?.password) {
log.metadata.password = "[REDACTED]";
}
// Add custom metadata
log.metadata = {
...log.metadata,
appVersion: "1.2.3",
};
return log;
},
});
// Drop logs conditionally
const logger = new FlareLog({
beforeSend: (log) => {
// Drop health check logs
if (log.message?.includes("/health")) {
return false;
}
// Drop logs below INFO in production
if (process.env.NODE_ENV === "production" &&
["TRACE", "DEBUG"].includes(log.level)) {
return false;
}
return log;
},
});PII Scrubbing (GDPR Compliance)
Automatically redact sensitive fields from metadata to prevent PII leakage.
import { FlareLog } from "@flarelog/sdk";
const logger = new FlareLog({
apiKey: "fl_your_api_key",
// Adds to the default scrub list: password, secret, token, apiKey, authorization, cookie, session, creditCard, ssn
scrubFields: ["password", "secret", "token", "email"],
});
logger.info("User signed up", {
email: "user@example.com", // → kept unless added to scrubFields
token: "abc123", // → "[REDACTED]" (default)
userId: "123", // → "123" (kept)
});Default scrub fields: password, secret, token, apiKey, authorization, auth, cookie, session, creditCard, ssn.
To scrub additional PII such as email, phone, or name, add them to scrubFields.
Handling Dropped Logs
Get notified when logs are dropped due to buffer overflow.
const logger = new FlareLog({
apiKey: "fl_your_api_key",
maxBatchSize: 100,
onDrop: (droppedCount) => {
console.warn(`Dropped ${droppedCount} logs`);
// Increment your monitoring metric here
},
});Sample Rate
Control log volume and costs.
// Send only 10% of logs
const logger = new FlareLog({
sampleRate: 0.1,
});
// Send 100% in development, 10% in production
const logger = new FlareLog({
sampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,
});Environment Metadata
Automatically track deployment context.
const logger = new FlareLog({
environment: "production", // or "staging", "development"
release: "1.2.3", // or git commit SHA
serverName: "web-01", // hostname or instance ID
});
// All logs include:
// { environment: "production", release: "1.2.3", serverName: "web-01" }Error Cause Chains
Capture nested error context (ES2022+).
const rootError = new Error("Database connection failed");
const apiError = new Error("API request failed", { cause: rootError });
const userError = new Error("Unable to load profile", { cause: apiError });
logger.logError(userError);
// Metadata includes full cause chain:
// {
// error: {
// message: "Unable to load profile",
// cause: {
// message: "API request failed",
// cause: {
// message: "Database connection failed"
// }
// }
// }
// }Child Loggers
Create scoped loggers with default context.
const requestLogger = logger.child({
source: "api",
traceId: "abc-123",
userId: "user_456",
});
requestLogger.info("Request started");
// Source: "api", metadata: { traceId: "abc-123", userId: "user_456" }
requestLogger.error("Database error");
// Inherits all parent context
// Nested children
const dbLogger = requestLogger.child({ source: "database" });
dbLogger.info("Query executed");
// Source: "database", metadata: { traceId: "abc-123", userId: "user_456" }Capture Patterns
Async Operations
// Capture errors and rethrow (default)
const result = await logger.capture(
() => fetchUserData(userId),
{ label: "Fetch user", metadata: { userId } }
);
// Capture without rethrowing
const result = await logger.capture(
() => fetchUserData(userId),
{ rethrow: false, label: "Fetch user" }
);
// Returns undefined on error instead of throwing
// Capture with custom level
await logger.capture(
() => riskyOperation(),
{ level: "WARN", label: "Risky operation" }
);Sync Operations
const result = logger.captureSync(
() => parseJSON(data),
{ label: "Parse JSON", metadata: { dataLength: data.length } }
);Request Wrapping
For Cloudflare Workers and similar environments.
export default {
async fetch(request, env, ctx) {
return logger.withRequest(
{
request,
traceId: request.headers.get("x-trace-id") || crypto.randomUUID(),
metadata: { region: env.CF_REGION }
},
ctx,
async () => {
// Your handler code
// All logs include request context
return new Response("OK");
}
);
}
};Deduplication
Prevent duplicate error spam.
const logger = new FlareLog({
autoCapture: {
globalErrors: true,
dedupWindowMs: 10000, // 10 seconds
},
});
// Same error within 10 seconds is only logged onceConsole Capture
Intercept console methods automatically.
const logger = new FlareLog({
autoCapture: {
console: true, // Capture error and warn
// Or configure specifically:
console: {
levels: ["error", "warn", "info"], // Capture these levels
source: "app-console", // Custom source tag
includeArgs: true, // Include console arguments
}
}
});
// Now console.error("Something failed") is captured as a logManual Flushing
Ensure logs are sent immediately.
// Flush all pending logs
await logger.flush();
// In Cloudflare Workers
ctx.waitUntil(logger.flush());
// Before page unload
window.addEventListener("beforeunload", () => {
logger.flush();
});Cleanup
Remove event listeners and restore console.
// Clean up when shutting down
logger.destroy();
// Or clean up specific handlers
const cleanup = logger.installGlobalHandlers();
// Later...
cleanup();Complete Configuration Example
import { FlareLog } from "@flarelog/sdk";
const logger = new FlareLog({
// Required
apiKey: "fl_your_api_key",
// Optional
endpoint: "https://flarelog.dev",
level: "DEBUG",
batchSize: 10, // flush after N logs. Default: 50 (Node), 1 (Worker/Edge)
flushIntervalMs: 5000, // also flush on a timer. Default: 5000ms (Node), 0 (Worker)
// workerMode: true, // Use SimpleProcessor; recommended for Workers/edge runtimes
debug: false,
defaultSource: "",
includeTimestamps: true,
// Environment
environment: "production",
release: "1.2.3",
serverName: "web-01",
// Sampling
sampleRate: 1.0,
// Auto-capture
// NOTE: http, navigation, and clicks are NOT YET IMPLEMENTED — omit them.
autoCapture: {
console: { levels: ["error", "warn"], source: "console" },
globalErrors: true,
rejections: true,
dedupWindowMs: 5000,
},
// Data sanitization
beforeSend: (log) => {
// Scrub PII
if (log.metadata?.password) delete log.metadata.password;
if (log.metadata?.token) log.metadata.token = "[REDACTED]";
// Add custom fields
log.metadata = {
...log.metadata,
region: process.env.REGION,
};
return log;
},
});