@luminpdf/browser-logger
v0.4.0
Published
A browser-based logger client with pluggable providers (Datadog)
Readme
LoggerClient Usage Guide
A TypeScript logging client for Datadog Browser Logs with automatic attribute enrichment and URL sanitization.
Features
- Singleton Pattern: Ensures a single logger instance across your application
- Type-Safe: Full TypeScript support with proper type definitions
- Auto-enrichment: Automatically adds common browser attributes to all logs
- URL Sanitization: Removes sensitive tokens from URLs before sending
- Anonymous User Tracking: Supports anonymous user ID tracking
- Simple API: Clean, intuitive methods for logging at different levels
Installation
npm install @luminpdf/browser-logger
# or
yarn add @luminpdf/browser-logger
# or
pnpm add @luminpdf/browser-loggerBasic Usage
import { LoggerClient } from "@luminpdf/browser-logger";
// Use the static factory method to get the singleton instance
const logger = LoggerClient.create(
{
disableInDevelopment: true,
datadog: {
clientToken: process.env.DATADOG_CLIENT_TOKEN,
service: "my-app",
env: process.env.ENV,
version: process.env.BUILD_NUMBER,
site: "datadoghq.com",
forwardErrorsToLogs: true,
sampleRate: 100,
},
},
() => cookieManager.anonymousUserId // Optional: function to get anonymous user ID
);
// Log messages at different levels
logger.info({ message: "User logged in", userId: "123" });
logger.debug({ message: "API response received", endpoint: "/api/users" });
logger.warn({ message: "Slow response time", duration: 3000 });
logger.error({ message: "API call failed", error: "Network timeout" });
// You can also log simple strings
logger.info("Application started");Note: Calling LoggerClient.create() multiple times will always return the same singleton instance, ensuring consistent configuration across your application.
Advanced Usage
Logging Different Message Types
// Log a simple string
logger.info("Simple message");
// Log an object with multiple properties
logger.error({
message: "Payment processing failed",
userId: "user-123",
amount: 99.99,
paymentMethod: "credit_card",
errorCode: "INSUFFICIENT_FUNDS",
});
// Log with dynamic data
const requestData = { endpoint: "/api/data", method: "POST" };
logger.debug({
message: "API request sent",
...requestData,
timestamp: Date.now(),
});Checking Logger Status
// Check if logger is configured
if (logger.isClientConfigured()) {
console.log("Logger is ready");
}
// Get current configuration
const config = logger.getConfig();
console.log("Logger config:", config);Resetting the Instance (Testing Only)
For testing purposes, you can reset the singleton instance:
// Reset the singleton (typically only used in tests)
LoggerClient.resetInstance();
// Now you can create a new instance with different config
const newLogger = LoggerClient.create({
/* different config */
});API Reference
Static Methods
LoggerClient.create(config: LoggerClientConfig, getAnonymousUserId?: () => string | undefined): LoggerClient
Returns the singleton instance of LoggerClient. Subsequent calls return the same instance.
Parameters:
config: Logger configuration (required)getAnonymousUserId: Optional function that returns the anonymous user ID
LoggerClient.resetInstance(): void
Resets the singleton instance. Useful for testing purposes only.
Instance Methods
info(message: LogMessage): void
Logs an info-level message. Message can be a string or an object.
debug(message: LogMessage): void
Logs a debug-level message. Message can be a string or an object.
warn(message: LogMessage): void
Logs a warning-level message. Message can be a string or an object.
error(message: LogMessage): void
Logs an error-level message. Message can be a string or an object.
getConfig(): Readonly<Required<LoggerClientConfig>>
Returns the current configuration.
isClientConfigured(): boolean
Returns whether the client has been configured.
getProvider(): DatadogProvider
Returns the underlying DatadogProvider instance.
Configuration Options
LoggerClientConfig
| Option | Type | Default | Description |
| ---------------------- | --------------- | ------- | ----------------------------------------- |
| datadog | DatadogConfig | - | Datadog-specific configuration (required) |
| disableInDevelopment | boolean | true | Whether to disable logging in development |
DatadogConfig
| Option | Type | Default | Description |
| --------------------- | --------- | ----------------- | --------------------------------------- |
| clientToken | string | - | Datadog client token (required) |
| service | string | - | Service name for logging (required) |
| env | string | - | Environment (e.g., production, staging) |
| site | string | 'datadoghq.com' | Datadog site |
| version | string | '1.0.0' | Application version/build number |
| forwardErrorsToLogs | boolean | true | Forward console errors to logs |
| sampleRate | number | 100 | Sample rate percentage (0-100) |
Auto-Enrichment
All log messages are automatically enriched with common attributes from @luminpdf/signing-miscellaneous:
userOS: Operating systemuserBrowser: Browser nameurl: Current page URLclientType: Client type (desktop, mobile, etc.)screenHeightPx: Screen height in pixelsscreenWidthPx: Screen width in pixelsbrowserLanguage: Browser languagebrowser: User agent stringanonymousUserId: Anonymous user ID (if provided)
URL Sanitization
The logger automatically removes sensitive token parameters from URLs before sending logs to Datadog:
// Before: https://example.com/page?token=secret123&other=value
// After: https://example.com/page?other=valueMigration Examples
From bananasign-web/logger.js
// Before
import { datadogLogs } from '@datadog/browser-logs';
import set from 'lodash/set';
import { cookieManager } from 'src/helpers/cookieManager';
class Logger {
constructor() {
if (process.env.ENV !== BANANSIGN_ENV.LOCAL) {
this.initialize();
}
}
async initialize() {
datadogLogs.init(this.getConfiguration());
this.instance = datadogLogs;
}
getConfiguration = () => {
return {
clientToken: process.env.DATADOG_CLIENT_TOKEN,
site: 'datadoghq.com',
service: 'bananasign-web',
env: process.env.ENV,
version: process.env.BUILD_NUMBER,
forwardErrorsToLogs: true,
sampleRate: 100,
beforeSend: this.handleBeforeSend,
};
};
handleBeforeSend = (event) => {
const eventOverride = event;
const { view: { url } } = eventOverride;
set(eventOverride, 'view.url', url.replace(/[&?]token=[^&]*/, ''));
set(eventOverride, 'anonymousUserId', cookieManager.anonymousUserId);
return eventOverride;
};
getCommonAttributes = () => {
return {
browser: window.navigator.userAgent,
anonymousUserId: cookieManager.anonymousUserId,
};
};
info(message) {
if (this.instance) {
this.instance.logger.info(JSON.stringify({ ...message, ...this.getCommonAttributes() }));
}
}
// ... other methods
}
export default new Logger();
// After
import { LoggerClient } from '@luminpdf/browser-logger';
import { cookieManager } from 'src/helpers/cookieManager';
const logger = LoggerClient.create(
{
disableInDevelopment: true,
datadog: {
clientToken: process.env.DATADOG_CLIENT_TOKEN,
site: 'datadoghq.com',
service: 'bananasign-web',
env: process.env.ENV,
version: process.env.BUILD_NUMBER,
forwardErrorsToLogs: true,
sampleRate: 100,
},
},
() => cookieManager.anonymousUserId
);
export default logger;
// Usage is the same
logger.info({ message: 'User action', action: 'click' });
logger.error({ message: 'Error occurred', error: err.message });How It Works
- Singleton Pattern: The first call to
LoggerClient.create()creates the instance - Initialization: Datadog Logs SDK is initialized with your configuration (unless disabled in development)
- Auto-enrichment: Every log call automatically includes common browser attributes
- Before-send Hook: URLs are sanitized and anonymous user ID is added before sending to Datadog
License
ISC
