Skip to content

v1.2.1 - Add Tag-Based Log Filtering

Choose a tag to compare

@onamfc onamfc released this 15 Nov 04:57
· 9 commits to main since this release

Summary

This PR adds optional tag-based filtering functionality to @onamfc/developer-log, allowing developers to filter logs by category/feature during development. This feature helps reduce console noise and enables focused debugging without commenting out code.

Key Features

Tag-Based Filtering

  • Add optional tags to any log method using { tag: 'category' } as the last parameter
  • Filter which logs appear based on enabled tags
  • Untagged logs always show (maintains backward compatibility)

Flexible Configuration

  • Auto-load: Automatically loads config from project root (e.g., dev-log.config.json)
  • Programmatic: dev.configure({ enabledTags: ['database', 'api'] })
  • Explicit file loading: dev.loadConfig('./path/to/config.json')

Smart Filtering Logic

  • No config: All logs show (tagged and untagged)
  • With config: Only untagged logs + enabled tags show
  • Production: Everything suppressed (existing behavior preserved)

Usage Examples

Basic Usage

import { dev } from '@onamfc/developer-log';

// Tagged logs
dev.log('Database connected', { tag: 'database' });
dev.error('API request failed', error, { tag: 'api' });

// Untagged logs (always show)
dev.log('Application started');

Auto-Load Configuration (Recommended)

// 1. Create dev-log.config.json in your project root:
// {
//   "enabledTags": ["database", "auth"]
// }

// 2. Just import and use - config loads automatically!
import { dev } from '@onamfc/developer-log';

dev.log('Query executed', { tag: 'database' }); // Shows if enabled

Supported auto-load file names (checked in order):

  • dev-log.config.json
  • .devlogrc.json
  • .devlogrc

Manual Configuration

// Programmatic configuration
dev.configure({ enabledTags: ['database', 'auth'] });

// Or load from a specific path
dev.loadConfig('./config/dev-log.config.json');

Config File Format

{
  "enabledTags": ["database", "api", "auth"]
}

Where to place dev.configure() (if using programmatic config):

  • Main entry point: index.ts, app.ts, server.ts, main.ts
  • Before any code that uses tagged logs
  • Framework-specific locations:
    • Express/Node.js: Top of server file
    • Next.js: _app.tsx or layout.tsx
    • React: index.tsx or App.tsx
    • NestJS: main.ts before app.listen()

Real-World Scenarios

Debugging a specific feature:

dev.log('Fetching user profile', { tag: 'profile' });
dev.log('Loading dashboard', { tag: 'dashboard' });

// Focus on profile debugging
dev.configure({ enabledTags: ['profile'] });

Dynamic configuration via environment:

if (process.env.DEBUG_TAGS) {
  dev.configure({
    enabledTags: process.env.DEBUG_TAGS.split(',')
  });
}
// Run with: DEBUG_TAGS=database,api npm start

Technical Implementation

New Interfaces

interface LogOptions {
  tag?: string;
}

interface Config {
  enabledTags?: string[];
}

New Methods

  • dev.configure(config: Config): void - Programmatic configuration
  • dev.loadConfig(filePath: string): void - Load config from JSON file
  • autoLoadConfig() - Internal function that runs at module import (not exported)

Core Logic

  1. Auto-Load: At module import time, searches for config files in project root (dev-log.config.json, .devlogrc.json, .devlogrc)
  2. Tag Extraction: Checks if last argument is a plain object with tag property
  3. Tag Stripping: Removes options object before passing to console methods
  4. Filtering: Compares tag against enabled tags Set (O(1) lookup)
  5. Production Override: Production check always takes precedence

Files Changed

Modified

  • src/index.ts

    • Added imports for fs and path modules
    • Added LogOptions and Config interfaces
    • Implemented configuration state management
    • Created autoLoadConfig() function for automatic config detection and loading
    • Created extractTagFromArgs() helper function
    • Implemented createLogMethod() wrapper with filtering logic
    • Added configure() and loadConfig() methods
    • Call autoLoadConfig() at module initialization
    • Updated all console method bindings to use wrapper
  • README.md

    • Updated package description
    • Added tag examples to Usage section
    • Added comprehensive Tag-Based Filtering section
    • Added Practical Examples with 3 real-world scenarios
    • Updated "Why Use This?" section with new benefits
    • Enhanced Migration section with tag adoption guide

Breaking Changes

None. This is a fully backward-compatible change:

  • Existing code without tags works exactly as before
  • Default behavior unchanged (all logs show when no config is set)
  • Production behavior unchanged (all logs suppressed)

Migration Guide

No changes required for existing users

The package remains fully backward compatible. Existing code continues to work:

// This still works exactly as before
dev.log('Hello, world!');
dev.error('An error', error);

Optional: Adopt tag filtering

Users can progressively adopt tags where useful:

// Step 1: Keep existing logs as-is (they'll always show)
dev.log('App started'); // No tag - always shows

// Step 2: Add tags to logs you want to filter
dev.log('Query executed', result, { tag: 'database' });
dev.error('Request failed', error, { tag: 'api' });

// Step 3: Configure filtering as needed
dev.configure({ enabledTags: ['database'] });
// Now: 'App started' and database logs show, api logs hidden