Debugging
ReActive Record provides a comprehensive logging system that helps you debug your application by tracking database operations, model changes, and relationship updates.
Logger Configuration
The logger can be configured in two ways during database initialization:
- Level-specific logging through
initial.loggers
- Severity-based subscriptions through
initial.subscriptions
import { ReactiveDatabase } from '@nhtio/web-re-active-record'
const db = new ReactiveDatabase({
// ... other config options
initial: {
// Level-specific loggers
loggers: {
error: [
(...args) => console.error(...args)
],
info: [
(...args) => console.info(...args)
]
},
// Severity-based subscriptions
// Will receive all logs at or above the specified level
subscriptions: [
// Subscribe to error and all more severe levels (emerg, alert, crit)
['error', (msg) => console.log(msg)],
// Subscribe to warning and all more severe levels
['warning', (msg) => errorTrackingService.capture(msg)]
]
}
})
Level-Specific Logging
Use loggers
when you want handlers for specific log levels:
{
loggers: {
error: [(...args) => handleError(...args)],
info: [(...args) => logInfo(...args)],
debug: [(...args) => console.debug(...args)]
}
}
Severity-Based Subscriptions
Use subscriptions
when you want handlers for all logs at or above a certain severity level:
{
subscriptions: [
// Will receive emerg, alert, crit, and error logs
['error', (...args) => handleSevereIssues(...args)],
// Will receive all logs from warning up to emerg
['warning', (...args) => trackIssues(...args)]
]
}
You can then use the logger
accessor on the database instance to make changes to the logger's configuration during the runtime of your application.
db.logger.off('info', someCallback)
db.logger.once('debug', someDebugCallback)
db.logger.subscribe('error', someCallbackForAllLogLevelsOverError)
For more information about the logger, see the logger api documentation.
Log Events
ReActive Record provides eight independent log events that you can subscribe to:
Event | Numeric Value | Description | Example Use Case |
---|---|---|---|
emerg | 0 | System is unusable | Critical database corruption |
alert | 1 | Action must be taken immediately | Severe data integrity issues |
crit | 2 | Critical conditions | Failed relationship synchronization |
error | 3 | Error conditions | Query failures, invalid operations |
warning | 4 | Warning conditions | Deprecated usage, performance issues |
notice | 5 | Normal but significant condition | Schema changes, version updates |
info | 6 | Informational messages | Successful operations, sync events |
debug | 7 | Debug-level messages | Detailed operation tracking |
Each log event operates independently. You can subscribe to any combination of events based on your needs. There is no hierarchical relationship between events - subscribing to one event does not automatically subscribe you to others.
Understanding the Levels
The log levels are inspired by syslog severity levels and is meant to represent the importance of the message in relation to your applications usage of the database. The general rule is that the lower the numeric value, the more severe the message.
Accessing the Logger
You can access the logger instance through the database object:
const db = new ReactiveDatabase(config)
const logger = db.logger
Subscribing to Log Events
Subscribe to specific log events after initialization:
// Subscribe to multiple events independently
db.logger
.on('error', (...args) => {
// Handle error events
errorTrackingService.capture(...args)
})
.on('info', (...args) => {
// Handle info events
customLogger.info(...args)
})
.on('debug', (...args) => {
// Handle debug events
console.debug('[ReActive Record]:', ...args)
})
// Events are independent - you can subscribe to any combination
db.logger
.on('emerg', emergencyHandler)
.on('crit', criticalHandler)
// You don't need to subscribe to all events
// .on('alert', alertHandler)
// .on('error', errorHandler)
.on('warning', warningHandler)
Unsubscribing from Log Events
Remove specific handlers or all handlers for an event:
// Remove a specific handler from an event
db.logger.off('error', specificHandler)
// Remove all handlers for an event
db.logger.off('debug')
// You can unsubscribe from events independently
db.logger
.off('emerg')
.off('error', errorHandler)
.off('warning')
One-Time Event Handlers
Register handlers that will be called only once for a specific event:
// Listen for the next occurrence of specific events
db.logger
.once('error', (...args) => {
console.error('First error encountered:', ...args)
})
.once('info', (...args) => {
console.info('First info received:', ...args)
})
// Each event's one-time handler operates independently
Error Handling
ReActive Record includes a separate error handler for managing asynchronous errors:
// Register an error handler
db.errorHandler.on((error: Error) => {
// Handle async errors
console.error('Async Error:', error)
})
// Remove error handler
db.errorHandler.off(handler)
If no error handlers are registered, errors will be thrown normally. When handlers are registered, errors are "swallowed" and passed to the handlers instead.
Debug Level Logging
The debug
log level is the most verbose level of logging and is typically used for detailed operation tracking during development.
Configure debug level logging by adding handlers to the debug
log level:
const db = new ReactiveDatabase({
// ... other config
initial: {
loggers: {
debug: [
(...args) => {
console.group('[ReActive Record Debug]')
console.debug(...args)
console.groupEnd()
}
]
}
}
})
What Gets Logged
Here's what each log level typically includes:
Debug Level
- Model instantiation
- Query execution
- Relationship loading
- Cache operations
- State changes
- Sync events
db.logger.on('debug', console.debug)
const user = await db.model('users').find(1)
// Debug: Finding user with id 1
// Debug: Loading user relationships
// Debug: User loaded successfully
Info Level
- Successful operations
- Model saves
- Relationship updates
- Cross-tab synchronization
db.logger.on('info', console.info)
await user.save()
// Info: User 1 saved successfully
// Info: Changes synchronized across tabs
Warning Level
- Deprecated feature usage
- Performance concerns
- Non-critical issues
db.logger.on('warning', console.warn)
// Warning: Large result set detected (>1000 records)
Error Level
- Query failures
- Validation errors
- Relationship errors
db.logger.on('error', console.error)
// Error: Failed to save user - validation error
Production Logging
For production environments, it's recommended to:
- Disable debug logging
- Only log errors and critical issues
- Use structured logging for better analysis
const db = new ReactiveDatabase({
// ... other config
initial: {
loggers: {
error: [(msg) => {
// Log to service
errorLoggingService.log(msg)
}],
crit: [(msg) => {
// Alert on critical issues
alertingService.notify(msg)
}]
}
}
})