A framework-agnostic logger with Slack integration for Node.js, Bun, and any JavaScript runtime.
- 🚀 Framework Independent - Works with Node.js, Bun, Deno, and any JS runtime
- 📢 Slack Integration - Send errors and warnings to Slack channels
- 🔍 Debug Filtering - Enable debug mode with pattern-based filtering
- ⚡ Multiple Transports - Console and Slack out of the box, extensible for custom transports
- 🎯 Error Classification - Automatically downgrade certain errors to warnings
- 🔒 Production Ready - Smart defaults for production environments
npm install @quave/logger
# or
bun add @quave/logger
# or
yarn add @quave/loggerimport { createLogger } from '@quave/logger';
const logger = createLogger({
appName: 'my-app',
});
logger.info('[API] Server started on port 3000');
logger.warn('[API] Rate limit approaching');
logger.error('[API] Database connection failed', error);
logger.debug('[API] Request details', { id: 123 });import { createLogger } from '@quave/logger';
const logger = createLogger({
// Application identification
appName: 'my-app',
environment: 'production', // 'development' | 'staging' | 'production'
// Debug configuration
debug: {
enabled: true,
filter: ['API', 'Database'], // Array of regex patterns
},
// Slack transport configuration
slack: {
enabled: true,
webhookUrl: process.env.SLACK_WEBHOOK_URL,
// Optional: different webhooks for different levels
webhookUrls: {
warn: process.env.SLACK_WARN_WEBHOOK,
error: process.env.SLACK_ERROR_WEBHOOK,
},
// Optional: custom channels per level
// If not specified, messages will be sent to the webhook's default channel
channels: {
info: '#app-logs',
warn: '#app-warnings',
error: '#app-errors',
'error-bg': '#app-errors-background',
},
// Skip Slack in development (default: true)
skipInDevelopment: true,
},
// Error messages to treat as warnings (won't trigger error alerts)
errorsToTreatAsWarnings: [
'User not found',
'Failed to fetch',
'Rate limit exceeded',
],
});You can also configure via environment variables:
NODE_ENV=production
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...Basic logging to console only.
logger.log('Server starting...');
logger.log('Config loaded', { port: 3000 });Informational messages to console only.
logger.info('[API] Request received', { method: 'POST', path: '/users' });Warning messages to console and Slack (in production).
logger.warn('[API] Rate limit approaching');
logger.warn('[API] Slow query detected', error);
logger.warn('[API] Custom alert', error, {
customChannel: 'alerts',
fields: { userId: '123' }
});Error messages to console and Slack (in production).
Important: Must be called with 1-2 arguments only.
logger.error('[API] Database connection failed');
logger.error('[API] Authentication failed', error);Background errors that don't block user actions. Routed to a separate Slack channel.
logger.errorBackground('[CRON] Sync job failed', error);
logger.errorBackground('[QUEUE] Message processing failed');When passing an error object to logger.error() or logger.errorBackground(), the logger expects a standard Error object or an object with compatible properties. The logger will extract the following fields:
Expected Error Object Structure:
{
message?: string | number, // Error message (required for standard Error objects)
reason?: string | number, // Custom error reason (optional)
details?: string | number, // Custom error details (optional)
stack?: string // Stack trace (optional, usually auto-generated)
}Valid Error Examples:
// Standard Error object (recommended)
try {
throw new Error('Something went wrong');
} catch (error) {
logger.error('[API] Operation failed', error);
}
// Custom error object with reason/details
const customError = {
message: 'Validation failed',
reason: 'Invalid input',
details: 'Email format is incorrect',
stack: new Error().stack
};
logger.error('[API] Validation error', customError);
// Error with just message
logger.error('[API] Failed', { message: 'Connection timeout' });Invalid Error Formats:
The logger will detect and handle invalid error formats gracefully. If an error object has unexpected types or structure, a fallback message will be sent to Slack explaining the format issue:
// ❌ These will trigger format warnings:
logger.error('[API] Failed', 'string error'); // Error is not an object
logger.error('[API] Failed', null); // Error is null
logger.error('[API] Failed', { message: {} }); // message is not string/number
logger.error('[API] Failed', { reason: [] }); // reason is not string/number
logger.error('[API] Failed', { stack: 123 }); // stack is not stringWhen an invalid format is detected:
- The original error message is still sent to Slack
- A warning is included explaining the format issue
- The raw error value is included for debugging
- The error type and format error details are logged
Best Practices:
-
Always use Error objects when possible:
try { // your code } catch (error) { logger.error('[API] Operation failed', error); // ✅ Good }
-
For custom errors, ensure properties are strings or numbers:
const customError = { message: String(errorMessage), // ✅ Convert to string reason: String(reason), // ✅ Convert to string details: JSON.stringify(data), // ✅ Serialize objects }; logger.error('[API] Custom error', customError);
-
Avoid passing non-object types directly:
// ❌ Bad logger.error('[API] Failed', 'error string'); logger.error('[API] Failed', 404); // ✅ Good logger.error('[API] Failed', new Error('error string')); logger.error('[API] Failed', { message: 'Status code: 404' });
Debug messages (only shown when debug mode is enabled and filter matches).
logger.debug('[API] Request details', { headers, body });
logger.debug('[Database] Query executed', { query, duration });Check if debug mode is enabled for a specific filter.
if (logger.isDebugModeOn('[API]')) {
// Do expensive debug computation
}Send a message directly to Slack (bypasses console).
await logger.sendToSlack({
message: 'Deployment completed successfully',
fields: { version: '1.2.3', environment: 'production' },
level: 'info',
customChannel: '#deployments',
});Get all registered transports.
const transports = logger.getTransports();
console.log(transports.map(t => t.name)); // ['console', 'slack']Add a custom transport at runtime.
import { BaseTransport } from '@quave/logger';
class MyTransport extends BaseTransport {
async send({ level, message, fields }) {
// Custom logic
}
}
logger.addTransport(new MyTransport());Create custom transports by extending BaseTransport:
import { BaseTransport, LogLevels } from '@quave/logger';
class DatadogTransport extends BaseTransport {
constructor(config) {
super({ ...config, name: 'datadog' });
this.apiKey = config.apiKey;
}
shouldHandle(level) {
// Only handle errors
return [LogLevels.ERROR, LogLevels.ERROR_BACKGROUND].includes(level);
}
async send({ level, message, fields, error }) {
// Send to Datadog API
await fetch('https://api.datadoghq.com/api/v1/logs', {
method: 'POST',
headers: {
'DD-API-KEY': this.apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
message,
level,
...fields,
}),
});
}
}
const logger = createLogger({
appName: 'my-app',
transports: [new DatadogTransport({ apiKey: process.env.DD_API_KEY })],
});The package also exports utilities you can use independently:
import {
// Error utilities
extractErrorFields,
shouldTreatAsWarning,
DEFAULT_WARNING_PATTERNS,
// Environment utilities
isDevelopment,
isProduction,
isStaging,
getEnvironment,
// Transport classes
BaseTransport,
ConsoleTransport,
SlackTransport,
LogLevels,
SlackLevels,
} from '@quave/logger';Messages sent to Slack include:
- text: The log message
- fields: Structured data including:
appName: Your application nameerrorMessage,errorReason,errorDetails,errorStack: Error info (if error provided)errorFormatInvalid,errorFormatError,errorRawValue: Error format validation info (if format is invalid)- Any custom fields you provide
Error Format Handling:
If an error object has an unexpected format, the logger will:
- Still send the original message to Slack
- Include a warning explaining the format issue
- Add fields like
errorFormatIssue,errorType, anderrorRawValuefor debugging - Preserve the original message in
originalMessagefield
This ensures that even when error objects are malformed, you'll still receive notifications in Slack with information about what went wrong.
See CHANGELOG.md for release history.
MIT © Quave