Filter Plugin
Control which logs are sent to transports based on level, namespace, or custom criteria.
Overview
The filter plugin allows you to reduce noise by filtering out unwanted logs before they reach transports. This is especially useful for:
- Production environments: Filter debug logs
- Performance: Reduce log volume
- Cost optimization: Minimize logs sent to paid services
- Security: Exclude sensitive namespaces
import { createFilterPlugin, createLogger } from '@crowlog/logger';
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
minLevel: 'info' // Only log info and above
})
]
});Filter by Log Level
Minimum Level
Allow only logs at or above a certain severity:
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({ minLevel: 'warn' })
]
});
logger.debug('Debug message'); // Filtered out
logger.info('Info message'); // Filtered out
logger.warn('Warning message'); // Logged ✓
logger.error('Error message'); // Logged ✓Level hierarchy: debug < info < warn < error
Maximum Level
Allow only logs at or below a certain severity:
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({ maxLevel: 'info' })
]
});
logger.debug('Debug message'); // Logged ✓
logger.info('Info message'); // Logged ✓
logger.warn('Warning message'); // Filtered out
logger.error('Error message'); // Filtered outLevel Range
Combine minLevel and maxLevel for a range:
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
minLevel: 'info',
maxLevel: 'warn'
})
]
});
logger.debug('Debug'); // Filtered out
logger.info('Info'); // Logged ✓
logger.warn('Warning'); // Logged ✓
logger.error('Error'); // Filtered outSpecific Levels Only
Use onlyLevels to allow specific levels:
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
onlyLevels: ['warn', 'error'] // Only warnings and errors
})
]
});
logger.debug('Debug'); // Filtered out
logger.info('Info'); // Filtered out
logger.warn('Warning'); // Logged ✓
logger.error('Error'); // Logged ✓Priority
When onlyLevels is specified, minLevel and maxLevel are ignored.
Filter by Namespace
Exclude Namespaces
Filter out specific namespaces:
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
excludedNamespaces: ['debug-utils', 'test-helpers', 'dev-tools']
})
]
});
// These loggers are filtered out
const debugLogger = logger.createChildLogger({ namespace: 'debug-utils' });
const testLogger = logger.createChildLogger({ namespace: 'test-helpers' });
debugLogger.info('This is filtered out');
testLogger.info('This is also filtered out');
// Regular logger still works
logger.info('This is logged'); // ✓Allow Specific Namespaces Only
Use onlyNamespaces to allow only certain namespaces:
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
onlyNamespaces: ['api', 'database', 'auth']
})
]
});
const apiLogger = logger.createChildLogger({ namespace: 'api' });
const cacheLogger = logger.createChildLogger({ namespace: 'cache' });
apiLogger.info('API request'); // Logged ✓
cacheLogger.info('Cache hit'); // Filtered out (not in allowed list)Exact Match
Namespace filtering uses exact string matching. 'api' does not match 'api:v1'.
excludedNamespaces: ['api']; // Only excludes exactly 'api'For hierarchical filtering, use customFilter.
Custom Filtering
Custom Filter Function
Implement complex filtering logic:
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
customFilter: ({ context }) => {
// Only log if error exists or explicitly marked important
return context.data.error !== undefined || context.data.important === true;
}
})
]
});
logger.info('Regular message'); // Filtered out
logger.info({ important: true }, 'Critical update'); // Logged ✓
logger.error({ error: new Error('Failed') }, 'Error occurred'); // Logged ✓The customFilter function receives:
type FilterContext = {
context: {
level: 'debug' | 'info' | 'warn' | 'error';
message: string;
timestampMs: number;
namespace: string;
data: Record<string, unknown>;
};
};Filter by Message Content
createFilterPlugin({
customFilter: ({ context }) => {
// Exclude logs containing 'healthcheck'
return !context.message.toLowerCase().includes('healthcheck');
}
});Filter by Data Properties
createFilterPlugin({
customFilter: ({ context }) => {
// Only log slow requests
return context.data.duration && context.data.duration > 1000;
}
});Combining Filters
When multiple filter options are provided, ALL filters must pass (AND logic):
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
minLevel: 'info', // Must be info or above
excludedNamespaces: ['debug-utils'], // AND not from debug-utils
customFilter: ({ context }) => { // AND pass custom logic
return !context.message.includes('ignore');
}
})
]
});
// All conditions must be true for log to passPerformance Considerations
Efficient Filtering
// Avoid: Expensive operations in customFilter
createFilterPlugin({
customFilter: ({ context }) => {
// Bad: Regex on every log
const result = /complex-pattern/i.test(context.message);
// Bad: expensive check
const allowed = expensiveCheck(context.namespace);
return result && allowed;
}
});Pre-compute Where Possible
// Good: Pre-compute expensive operations
const excludedPaths = new Set(['/health', '/metrics', '/ready']);
createFilterPlugin({
customFilter: ({ context }) => {
return !excludedPaths.has(context.data.path);
}
});