LogStack Examples

Real-world examples and implementations for various use cases

๐Ÿš€ Basic Setup

Simple setup for small applications with local storage:

basic-setup.js

const { init, createDailyJobs, saveApiLog } = require('logstack');

async function basicSetup() {
  const config = {
    dbUri: 'mongodb://localhost:27017/basic-logs',
    uploadProvider: 'local',
    outputDirectory: './logs',
    retention: {
      dbRetentionDays: 7,
      fileRetentionDays: 30
    }
  };

  try {
    await init(config);
    await createDailyJobs();
    console.log('โœ… Basic LogStack setup complete!');
    
    // Example: Save a log
    await saveApiLog({
      method: 'GET',
      path: '/api/users',
      statusCode: 200,
      responseTime: 45,
      userId: 'user123'
    });
    
  } catch (error) {
    console.error('โŒ Setup failed:', error);
  }
}

basicSetup();

Expected Output:

โœ… Database connected
โœ… Local storage configured
โœ… Daily jobs created (24 hourly tasks)
โœ… API log saved successfully
๐Ÿ“ Files will be stored in: ./logs/

๐Ÿญ Production Ready Implementation

Complete production setup with AWS S3, monitoring, and error handling:

production-implementation.js

const { init, createDailyJobs } = require('logstack');
const express = require('express');

class ProductionLogStack {
  constructor() {
    this.config = {
      dbUri: process.env.MONGODB_URI,
      uploadProvider: 's3',
      
      // Daily folder structure with organized sub-folders
      folderStructure: {
        type: 'daily',
        subFolders: {
          enabled: true,
          byHour: true,
          byStatus: true,
          custom: ['processed']
        },
        naming: {
          prefix: 'production-logs',
          dateFormat: 'YYYY-MM-DD',
          includeTime: false
        }
      },
      
      // Security settings
      dataMasking: {
        enabled: true,
        maskPasswords: true,
        maskEmails: true,
        customFields: ['token', 'secret', 'authorization']
      },
      
      // Retention policies
      retention: {
        enabled: true,
        dbRetentionDays: 14,
        fileRetentionDays: 180,
        cleanupIntervalHours: 24
      },
      
      // AWS S3 configuration
      s3: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        region: process.env.AWS_REGION || 'us-east-1',
        bucket: process.env.S3_BUCKET,
        serverSideEncryption: 'AES256'
      },
      
      // Production collections
      collections: {
        jobsCollectionName: 'production_jobs',
        logsCollectionName: 'production_logs',
        apiLogsCollectionName: 'production_api_logs'
      }
    };
  }

  async initialize() {
    try {
      console.log('๐Ÿš€ Initializing Production LogStack...');
      
      // Validate environment
      this.validateEnvironment();
      
      // Initialize LogStack
      await init(this.config);
      await createDailyJobs();
      
      // Setup health check endpoint
      this.setupHealthCheck();
      
      // Setup monitoring
      this.setupMonitoring();
      
      console.log('โœ… Production LogStack initialized successfully!');
      return true;
      
    } catch (error) {
      console.error('๐Ÿ’ฅ Production initialization failed:', error);
      throw error;
    }
  }

  validateEnvironment() {
    const required = [
      'MONGODB_URI',
      'AWS_ACCESS_KEY_ID', 
      'AWS_SECRET_ACCESS_KEY',
      'S3_BUCKET'
    ];
    
    const missing = required.filter(env => !process.env[env]);
    if (missing.length > 0) {
      throw new Error(`Missing environment variables: ${missing.join(', ')}`);
    }
  }

  setupHealthCheck() {
    const app = express();
    
    app.get('/health', async (req, res) => {
      try {
        // Check database connection
        const dbStatus = await this.checkDatabase();
        
        // Check S3 connectivity
        const s3Status = await this.checkS3();
        
        res.json({
          status: 'healthy',
          timestamp: new Date().toISOString(),
          database: dbStatus,
          storage: s3Status,
          uptime: Math.floor(process.uptime()),
          memory: Math.round(process.memoryUsage().heapUsed / 1024 / 1024)
        });
        
      } catch (error) {
        res.status(503).json({
          status: 'unhealthy',
          error: error.message,
          timestamp: new Date().toISOString()
        });
      }
    });
    
    app.listen(3000, () => {
      console.log('๐Ÿฅ Health check available at http://localhost:3000/health');
    });
  }

  async checkDatabase() {
    // Implementation for database health check
    return 'connected';
  }

  async checkS3() {
    // Implementation for S3 health check
    return 'accessible';
  }

  setupMonitoring() {
    // Log system metrics every 5 minutes
    setInterval(() => {
      const metrics = {
        timestamp: new Date().toISOString(),
        memory: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
        uptime: Math.floor(process.uptime() / 60),
        cpu: process.cpuUsage()
      };
      
      console.log('๐Ÿ“Š System Metrics:', JSON.stringify(metrics));
    }, 5 * 60 * 1000);

    // Graceful shutdown
    process.on('SIGTERM', () => {
      console.log('๐Ÿ“ค Received SIGTERM, shutting down gracefully...');
      process.exit(0);
    });
  }
}

// Initialize and start
async function start() {
  const logStack = new ProductionLogStack();
  await logStack.initialize();
}

if (require.main === module) {
  start().catch(console.error);
}

module.exports = ProductionLogStack;

โ˜๏ธ Multi-Provider Setup

Configure multiple storage providers with fallback support:

multi-provider.js

const { init, createDailyJobs } = require('logstack');

async function multiProviderSetup() {
  // Primary configuration with S3
  const primaryConfig = {
    dbUri: process.env.MONGODB_URI,
    uploadProvider: 's3',
    s3: {
      accessKeyId: process.env.AWS_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
      region: 'us-east-1',
      bucket: 'primary-logs-bucket'
    }
  };

  // Fallback configuration with local storage
  const fallbackConfig = {
    dbUri: process.env.MONGODB_URI,
    uploadProvider: 'local',
    outputDirectory: './fallback-logs'
  };

  // Secondary S3 backup configuration
  const secondaryS3Config = {
    dbUri: process.env.MONGODB_URI,
    uploadProvider: 's3',
    s3: {
      accessKeyId: process.env.AWS_SECONDARY_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECONDARY_SECRET_ACCESS_KEY,
      region: 'us-west-2',
      bucket: 'secondary-logs-bucket'
    }
  };

  try {
    console.log('๐Ÿ”„ Attempting primary provider (S3)...');
    await init(primaryConfig);
    console.log('โœ… Primary provider initialized');
    
  } catch (s3Error) {
    console.log('โš ๏ธ Primary provider failed, trying secondary S3...');
    
    try {
      await init(secondaryS3Config);
      console.log('โœ… Secondary S3 provider initialized');
      
    } catch (secondaryError) {
      console.log('โš ๏ธ Secondary S3 failed, using local storage...');
      await init(fallbackConfig);
      console.log('โœ… Local fallback provider initialized');
    }
  }

  await createDailyJobs();
  console.log('๐Ÿ“… Daily jobs created successfully');
}

// Provider-specific configurations
const providerConfigs = {
  s3: {
    uploadProvider: 's3',
    s3: {
      accessKeyId: process.env.AWS_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
      region: 'us-west-2',
      bucket: 'logs-s3-bucket',
      storageClass: 'STANDARD_IA'  // Cost-effective for logs
    }
  },

  s3_backup: {
    uploadProvider: 's3',
    s3: {
      accessKeyId: process.env.AWS_BACKUP_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_BACKUP_SECRET_ACCESS_KEY,
      region: 'eu-west-1',
      bucket: 'logs-backup-bucket',
      storageClass: 'GLACIER'  // Long-term storage
    }
  },

  local: {
    uploadProvider: 'local',
    outputDirectory: './production-logs',
    preserveLocalFiles: true,
    compression: {
      enabled: true,
      format: 'gzip'
    }
  }
};

// Function to switch providers dynamically
async function switchProvider(providerName) {
  const config = {
    ...providerConfigs[providerName],
    dbUri: process.env.MONGODB_URI
  };

  try {
    await init(config);
    console.log(`โœ… Switched to ${providerName} provider`);
    return true;
  } catch (error) {
    console.error(`โŒ Failed to switch to ${providerName}:`, error.message);
    return false;
  }
}

// Command line interface
if (require.main === module) {
  const provider = process.argv[2] || 'multi';
  
  if (provider === 'multi') {
    multiProviderSetup();
  } else if (providerConfigs[provider]) {
    switchProvider(provider);
  } else {
    console.log('Available providers: s3, s3_backup, local, multi');
  }
}

module.exports = { multiProviderSetup, switchProvider, providerConfigs };

๐Ÿ”’ Advanced Data Masking

Comprehensive data masking for sensitive information:

data-masking-example.js

const { init, saveApiLog } = require('logstack');

async function dataMaskingExample() {
  const config = {
    dbUri: 'mongodb://localhost:27017/secure-logs',
    uploadProvider: 'local',
    outputDirectory: './secure-logs',
    
    dataMasking: {
      enabled: true,
      
      // Basic masking options
      maskEmails: true,
      maskIPs: false,            // Keep IPs for debugging
      maskPasswords: true,
      showLastChars: 2,          // Show last 2 characters for emails
      maskingChar: '*',
      
      // Custom field patterns
      customFields: [
        'token', 'secret', 'key', 'authorization',
        'cookie', 'session', 'apiKey', 'accessToken'
      ],
      
      // Advanced pattern matching
      patterns: {
        // Credit card numbers
        creditCard: {
          pattern: /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
          replacement: '****-****-****-$1',
          preserveLast: 4
        },
        
        // Phone numbers
        phone: {
          pattern: /(\+?\d{1,3}[\s-]?)?\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}/g,
          replacement: '***-***-$1',
          preserveLast: 4
        },
        
        // Social Security Numbers
        ssn: {
          pattern: /\b\d{3}-\d{2}-\d{4}\b/g,
          replacement: '***-**-$1',
          preserveLast: 4
        },
        
        // API Keys (various formats)
        apiKey: {
          pattern: /\b[A-Za-z0-9]{32,}\b/g,
          replacement: '****...$1',
          preserveLast: 6
        }
      },
      
      // Context-aware masking
      contextRules: {
        // Mask differently based on user role
        admin: {
          showEmails: true,
          showIPs: true,
          maskPasswords: true
        },
        user: {
          showEmails: false,
          showIPs: false,
          maskPasswords: true
        }
      }
    }
  };

  await init(config);

  // Test data with sensitive information
  const testLogs = [
    {
      method: 'POST',
      path: '/api/login',
      statusCode: 200,
      request: {
        email: 'user@example.com',
        password: 'mySecretPassword123',
        rememberMe: true
      },
      response: {
        token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ',
        user: {
          id: '12345',
          email: 'user@example.com',
          phone: '+1-555-123-4567'
        }
      },
      clientIP: '192.168.1.100',
      userAgent: 'Mozilla/5.0...'
    },
    
    {
      method: 'POST',
      path: '/api/payment',
      statusCode: 201,
      request: {
        amount: 99.99,
        creditCard: '4532-1234-5678-9012',
        cvv: '123',
        billingAddress: {
          name: 'John Doe',
          phone: '555-123-4567',
          ssn: '123-45-6789'
        }
      },
      response: {
        transactionId: 'tx_abc123xyz789',
        status: 'completed'
      }
    }
  ];

  // Save logs with automatic masking
  for (const log of testLogs) {
    await saveApiLog(log);
    console.log('โœ… Masked log saved:', log.path);
  }

  // Demonstrate different masking levels
  await demonstrateMaskingLevels();
}

async function demonstrateMaskingLevels() {
  console.log('\n๐Ÿ“‹ Masking Examples:\n');

  const originalData = {
    email: 'john.doe@company.com',
    password: 'SuperSecretPassword123!',
    creditCard: '4532-1234-5678-9012',
    phone: '+1-555-123-4567',
    ssn: '123-45-6789',
    token: 'sk_live_abc123def456ghi789'
  };

  // Simulate different masking configurations
  const maskingConfigs = [
    {
      name: 'Standard Masking',
      showLastChars: 0,
      description: 'Complete masking for maximum security'
    },
    {
      name: 'Partial Masking', 
      showLastChars: 4,
      description: 'Show last 4 characters for identification'
    },
    {
      name: 'Development Mode',
      showLastChars: 8,
      description: 'More visible for debugging'
    }
  ];

  maskingConfigs.forEach(config => {
    console.log(`\n${config.name} (${config.description}):`);
    console.log('โ”€'.repeat(50));
    
    // Simulate masking function
    const masked = applyMasking(originalData, config.showLastChars);
    
    Object.entries(masked).forEach(([key, value]) => {
      console.log(`${key.padEnd(12)}: ${value}`);
    });
  });
}

function applyMasking(data, showLastChars) {
  const mask = (str, chars = 0) => {
    if (!str || str.length <= chars) return '*'.repeat(8);
    return '*'.repeat(Math.max(str.length - chars, 4)) + 
           (chars > 0 ? str.slice(-chars) : '');
  };

  return {
    email: showLastChars > 0 ? mask(data.email, 4) : '****@****.**',
    password: mask(data.password, 0),  // Never show password chars
    creditCard: mask(data.creditCard, showLastChars),
    phone: mask(data.phone, showLastChars),
    ssn: mask(data.ssn, showLastChars),
    token: mask(data.token, Math.min(showLastChars, 6))
  };
}

// Environment-based masking
async function environmentBasedMasking() {
  const isDevelopment = process.env.NODE_ENV === 'development';
  const isProduction = process.env.NODE_ENV === 'production';

  const config = {
    dbUri: process.env.MONGODB_URI,
    uploadProvider: 'local',
    outputDirectory: './logs',
    
    dataMasking: {
      enabled: isProduction,  // Only mask in production
      
      // Different rules for different environments
      ...(isDevelopment && {
        maskEmails: false,
        maskIPs: false,
        showLastChars: 8,
        patterns: {}  // Disable pattern matching in dev
      }),
      
      ...(isProduction && {
        maskEmails: true,
        maskIPs: true,
        showLastChars: 0,
        customFields: [
          'token', 'secret', 'key', 'authorization',
          'cookie', 'session', 'apiKey', 'accessToken',
          'password', 'pin', 'otp'
        ]
      })
    }
  };

  console.log(`๐ŸŒ Environment: ${process.env.NODE_ENV}`);
  console.log(`๐Ÿ”’ Masking enabled: ${config.dataMasking.enabled}`);
  
  await init(config);
}

if (require.main === module) {
  const mode = process.argv[2];
  
  switch(mode) {
    case 'demo':
      dataMaskingExample();
      break;
    case 'environment':
      environmentBasedMasking();
      break;
    default:
      dataMaskingExample();
  }
}

module.exports = { 
  dataMaskingExample, 
  environmentBasedMasking,
  demonstrateMaskingLevels 
};

๐Ÿ“ Custom Folder Structure

Advanced folder organization patterns:

custom-folder-structure.js

const { init, createDailyJobs } = require('logstack');

async function customFolderExample() {
  const configs = [
    {
      name: 'Microservice Architecture',
      config: {
        folderStructure: {
          type: 'daily',
          subFolders: {
            enabled: true,
            byService: true,      // Custom: by microservice
            byEnvironment: true,  // Custom: by environment
            byHour: true,
            custom: ['api-gateway', 'user-service', 'payment-service']
          },
          naming: {
            prefix: 'microservices',
            dateFormat: 'YYYY-MM-DD',
            includeEnvironment: true
          }
        }
      },
      expectedStructure: `
microservices_production_2025-09-02/
โ”œโ”€โ”€ api-gateway/
โ”‚   โ”œโ”€โ”€ hour-09-10/
โ”‚   โ”‚   โ”œโ”€โ”€ success/
โ”‚   โ”‚   โ””โ”€โ”€ failed/
โ”‚   โ””โ”€โ”€ hour-10-11/
โ”œโ”€โ”€ user-service/
โ”‚   โ””โ”€โ”€ hour-09-10/
โ””โ”€โ”€ payment-service/
    โ””โ”€โ”€ hour-09-10/`
    },

    {
      name: 'Multi-tenant SaaS',
      config: {
        folderStructure: {
          type: 'monthly',
          subFolders: {
            enabled: true,
            byTenant: true,       // Custom: by tenant
            byPlan: true,         // Custom: by subscription plan
            byRegion: true,       // Custom: by geographic region
            custom: ['enterprise', 'professional', 'starter']
          },
          naming: {
            prefix: 'saas-logs',
            dateFormat: 'YYYY-MM',
            includeTenant: true
          }
        }
      },
      expectedStructure: `
saas-logs_2025-09/
โ”œโ”€โ”€ tenant-acme-corp/
โ”‚   โ”œโ”€โ”€ enterprise/
โ”‚   โ”‚   โ”œโ”€โ”€ us-east/
โ”‚   โ”‚   โ””โ”€โ”€ eu-west/
โ”‚   โ””โ”€โ”€ professional/
โ”œโ”€โ”€ tenant-startup-inc/
โ”‚   โ””โ”€โ”€ starter/
โ””โ”€โ”€ tenant-global-ltd/
    โ””โ”€โ”€ enterprise/`
    },

    {
      name: 'E-commerce Platform',
      config: {
        folderStructure: {
          type: 'daily',
          subFolders: {
            enabled: true,
            byModule: true,       // Custom: by e-commerce module
            byOperation: true,    // Custom: by operation type
            byStatus: true,
            custom: ['orders', 'payments', 'inventory', 'users']
          },
          naming: {
            prefix: 'ecommerce',
            dateFormat: 'YYYY-MM-DD',
            includeModule: true
          }
        }
      },
      expectedStructure: `
ecommerce_2025-09-02/
โ”œโ”€โ”€ orders/
โ”‚   โ”œโ”€โ”€ create/
โ”‚   โ”‚   โ”œโ”€โ”€ success/
โ”‚   โ”‚   โ””โ”€โ”€ failed/
โ”‚   โ”œโ”€โ”€ update/
โ”‚   โ””โ”€โ”€ cancel/
โ”œโ”€โ”€ payments/
โ”‚   โ”œโ”€โ”€ process/
โ”‚   โ”œโ”€โ”€ refund/
โ”‚   โ””โ”€โ”€ dispute/
โ””โ”€โ”€ inventory/
    โ”œโ”€โ”€ check/
    โ””โ”€โ”€ update/`
    }
  ];

  for (const example of configs) {
    console.log(`\n๐Ÿ“ ${example.name} Structure:`);
    console.log('โ•'.repeat(50));
    
    const config = {
      dbUri: 'mongodb://localhost:27017/custom-folders',
      uploadProvider: 'local',
      outputDirectory: `./logs/${example.name.toLowerCase().replace(/\s+/g, '-')}`,
      ...example.config
    };

    try {
      await init(config);
      console.log('โœ… Configuration applied successfully');
      console.log('\n๐Ÿ“‚ Expected folder structure:');
      console.log(example.expectedStructure);
      
    } catch (error) {
      console.error('โŒ Configuration failed:', error.message);
    }
  }
}

// Dynamic folder structure based on request data
async function dynamicFolderStructure() {
  const config = {
    dbUri: 'mongodb://localhost:27017/dynamic-folders',
    uploadProvider: 'local',
    outputDirectory: './logs/dynamic',
    
    folderStructure: {
      type: 'custom',
      dynamicPattern: '${environment}/${service}/${date}/${hour}/${status}',
      variables: {
        environment: (req) => req.headers['x-environment'] || 'unknown',
        service: (req) => req.headers['x-service'] || 'default',
        date: () => new Date().toISOString().split('T')[0],
        hour: () => new Date().getHours().toString().padStart(2, '0'),
        status: (req, res) => res.statusCode >= 400 ? 'errors' : 'success'
      }
    },
    
    // Custom naming functions
    fileNaming: {
      pattern: '${service}_${timestamp}_${requestId}.json',
      variables: {
        service: (req) => req.headers['x-service'] || 'api',
        timestamp: () => Date.now(),
        requestId: (req) => req.headers['x-request-id'] || 'unknown'
      }
    }
  };

  await init(config);
  console.log('โœ… Dynamic folder structure initialized');
  
  // Simulate requests with different headers
  const simulatedRequests = [
    {
      headers: { 'x-environment': 'production', 'x-service': 'user-api' },
      path: '/api/users',
      statusCode: 200
    },
    {
      headers: { 'x-environment': 'staging', 'x-service': 'payment-api' },
      path: '/api/payments',
      statusCode: 500
    }
  ];

  for (const req of simulatedRequests) {
    const folderPath = generateDynamicPath(config.folderStructure, req);
    console.log(`๐Ÿ“ Request to ${req.path} โ†’ ${folderPath}`);
  }
}

function generateDynamicPath(structure, req, res = { statusCode: req.statusCode }) {
  let path = structure.dynamicPattern;
  
  for (const [variable, resolver] of Object.entries(structure.variables)) {
    const value = typeof resolver === 'function' ? resolver(req, res) : resolver;
    path = path.replace(`\${${variable}}`, value);
  }
  
  return path;
}

// Organized output with compression and rotation
async function organizedOutputExample() {
  const config = {
    dbUri: 'mongodb://localhost:27017/organized-logs',
    uploadProvider: 'local',
    outputDirectory: './logs/organized',
    
    folderStructure: {
      type: 'daily',
      subFolders: {
        enabled: true,
        byHour: true,
        byStatus: true,
        bySize: true,         // Split by file size
        custom: ['raw', 'processed', 'archived']
      },
      rotation: {
        enabled: true,
        maxFileSize: '10MB',  // Rotate when file exceeds 10MB
        maxFilesPerHour: 5,   // Maximum 5 files per hour
        compressionDelay: 60  // Compress files after 60 minutes
      }
    },
    
    compression: {
      enabled: true,
      format: 'gzip',
      level: 6,
      archiveOldFiles: true,
      deleteAfterCompression: true
    },
    
    monitoring: {
      enabled: true,
      logFolderSizes: true,
      alertOnLargeFiles: true,
      maxFolderSize: '1GB'
    }
  };

  await init(config);
  console.log('โœ… Organized output structure initialized');
  
  // Display expected organization
  console.log('\n๐Ÿ“‚ Organized structure with rotation:');
  console.log(`
logs/organized/
โ”œโ”€โ”€ logs_2025-09-02/
โ”‚   โ”œโ”€โ”€ hour-09/
โ”‚   โ”‚   โ”œโ”€โ”€ success/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ raw/
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ api_logs_001.json
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ api_logs_002.json
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ processed/
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ api_logs_processed.json
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ archived/
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ api_logs_001.json.gz
โ”‚   โ”‚   โ””โ”€โ”€ failed/
โ”‚   โ”‚       โ”œโ”€โ”€ raw/
โ”‚   โ”‚       โ””โ”€โ”€ processed/
โ”‚   โ””โ”€โ”€ hour-10/
โ”œโ”€โ”€ logs_2025-09-01/          // Previous day
โ”‚   โ””โ”€โ”€ archived/             // All compressed
โ””โ”€โ”€ statistics/
    โ”œโ”€โ”€ folder_sizes.json
    โ””โ”€โ”€ rotation_log.json`);
}

if (require.main === module) {
  const mode = process.argv[2];
  
  switch(mode) {
    case 'custom':
      customFolderExample();
      break;
    case 'dynamic':
      dynamicFolderStructure();
      break;
    case 'organized':
      organizedOutputExample();
      break;
    default:
      customFolderExample();
  }
}

module.exports = {
  customFolderExample,
  dynamicFolderStructure,
  organizedOutputExample,
  generateDynamicPath
};

๐Ÿš€ Express.js Integration

Complete integration with Express.js applications:

express-integration.js

const express = require('express');
const { init, saveApiLog, createDailyJobs } = require('logstack');

class ExpressLogStackIntegration {
  constructor(config = {}) {
    this.config = {
      dbUri: process.env.MONGODB_URI || 'mongodb://localhost:27017/express-logs',
      uploadProvider: 'local',
      outputDirectory: './logs/express',
      
      // Express-specific settings
      dataMasking: {
        enabled: true,
        maskPasswords: true,
        customFields: ['authorization', 'cookie', 'session']
      },
      
      // Filter settings
      filters: {
        skipRoutes: ['/health', '/metrics', '/favicon.ico'],
        skipMethods: ['OPTIONS'],
        skipStatusCodes: [], // Empty = log all status codes
        onlyLogErrors: false  // Set true to only log 4xx/5xx responses
      },
      
      ...config
    };
  }

  async initialize() {
    await init(this.config);
    await createDailyJobs();
    console.log('โœ… LogStack initialized for Express.js');
  }

  // Middleware factory
  createMiddleware(options = {}) {
    const {
      includeRequestBody = false,
      includeResponseBody = false,
      includeHeaders = true,
      maxBodySize = 10000,  // 10KB limit for body logging
      customExtractor = null
    } = options;

    return async (req, res, next) => {
      const startTime = Date.now();
      let requestBody = null;
      let responseBody = null;

      // Skip if route should be filtered
      if (this.shouldSkip(req)) {
        return next();
      }

      // Capture request body if needed
      if (includeRequestBody && req.body) {
        requestBody = JSON.stringify(req.body).length <= maxBodySize 
          ? req.body 
          : '[Body too large]';
      }

      // Capture response body if needed
      if (includeResponseBody) {
        const originalSend = res.send;
        res.send = function(body) {
          responseBody = typeof body === 'string' && body.length <= maxBodySize
            ? body 
            : '[Response too large]';
          return originalSend.call(this, body);
        };
      }

      // Continue to next middleware
      next();

      // Log after response is sent
      res.on('finish', async () => {
        try {
          const responseTime = Date.now() - startTime;
          
          let logData = {
            timestamp: new Date(),
            method: req.method,
            path: req.path,
            query: req.query,
            statusCode: res.statusCode,
            responseTime,
            userAgent: req.get('User-Agent'),
            clientIP: req.ip || req.connection.remoteAddress,
            referer: req.get('Referer')
          };

          // Add headers if requested
          if (includeHeaders) {
            logData.headers = this.sanitizeHeaders(req.headers);
          }

          // Add request body if captured
          if (requestBody) {
            logData.requestBody = requestBody;
          }

          // Add response body if captured
          if (responseBody) {
            logData.responseBody = responseBody;
          }

          // Add user info if available (from auth middleware)
          if (req.user) {
            logData.user = {
              id: req.user.id,
              email: req.user.email,
              role: req.user.role
            };
          }

          // Custom data extraction
          if (customExtractor && typeof customExtractor === 'function') {
            const customData = customExtractor(req, res);
            logData = { ...logData, ...customData };
          }

          await saveApiLog(logData);
          
        } catch (error) {
          console.error('โŒ Failed to log request:', error);
        }
      });
    };
  }

  shouldSkip(req) {
    const { skipRoutes, skipMethods, onlyLogErrors } = this.config.filters;
    
    // Skip specific routes
    if (skipRoutes.includes(req.path)) {
      return true;
    }
    
    // Skip specific methods
    if (skipMethods.includes(req.method)) {
      return true;
    }
    
    return false;
  }

  sanitizeHeaders(headers) {
    const sanitized = { ...headers };
    
    // Remove sensitive headers
    const sensitiveHeaders = [
      'authorization',
      'cookie',
      'x-api-key',
      'x-auth-token'
    ];
    
    sensitiveHeaders.forEach(header => {
      if (sanitized[header]) {
        sanitized[header] = '[REDACTED]';
      }
    });
    
    return sanitized;
  }

  // Error logging middleware
  createErrorMiddleware() {
    return async (error, req, res, next) => {
      try {
        const errorLog = {
          timestamp: new Date(),
          level: 'error',
          method: req.method,
          path: req.path,
          statusCode: res.statusCode || 500,
          error: {
            name: error.name,
            message: error.message,
            stack: error.stack
          },
          user: req.user ? { id: req.user.id } : null,
          clientIP: req.ip
        };

        await saveApiLog(errorLog);
        
      } catch (logError) {
        console.error('โŒ Failed to log error:', logError);
      }
      
      next(error);
    };
  }

  // Performance monitoring middleware
  createPerformanceMiddleware() {
    return (req, res, next) => {
      const startTime = process.hrtime.bigint();
      
      res.on('finish', async () => {
        const endTime = process.hrtime.bigint();
        const responseTime = Number(endTime - startTime) / 1000000; // Convert to ms
        
        // Log slow requests (> 1 second)
        if (responseTime > 1000) {
          await saveApiLog({
            timestamp: new Date(),
            level: 'warning',
            type: 'slow_request',
            method: req.method,
            path: req.path,
            responseTime,
            statusCode: res.statusCode,
            message: `Slow request detected: ${responseTime}ms`
          });
        }
      });
      
      next();
    };
  }
}

// Complete Express.js application example
async function createExpressApp() {
  const app = express();
  
  // Initialize LogStack
  const logStack = new ExpressLogStackIntegration({
    uploadProvider: 'local',
    outputDirectory: './logs/express-app'
  });
  
  await logStack.initialize();

  // Basic middleware
  app.use(express.json({ limit: '10mb' }));
  app.use(express.urlencoded({ extended: true }));

  // LogStack middlewares
  app.use(logStack.createMiddleware({
    includeRequestBody: true,
    includeResponseBody: false,
    includeHeaders: true
  }));
  
  app.use(logStack.createPerformanceMiddleware());

  // Health check endpoint (excluded from logging)
  app.get('/health', (req, res) => {
    res.json({ status: 'healthy', timestamp: new Date() });
  });

  // Sample API routes
  app.get('/api/users', async (req, res) => {
    // Simulate database query
    await new Promise(resolve => setTimeout(resolve, 100));
    
    res.json({
      users: [
        { id: 1, name: 'John Doe', email: 'john@example.com' },
        { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
      ]
    });
  });

  app.post('/api/users', async (req, res) => {
    const { name, email, password } = req.body;
    
    // Simulate user creation
    if (!name || !email) {
      return res.status(400).json({ error: 'Name and email required' });
    }
    
    res.status(201).json({
      id: Date.now(),
      name,
      email,
      created: new Date()
    });
  });

  app.post('/api/login', async (req, res) => {
    const { email, password } = req.body;
    
    // Simulate authentication
    if (email === 'admin@example.com' && password === 'admin123') {
      res.json({
        token: 'jwt_token_here',
        user: { id: 1, email, role: 'admin' }
      });
    } else {
      res.status(401).json({ error: 'Invalid credentials' });
    }
  });

  // Slow endpoint for performance testing
  app.get('/api/slow', async (req, res) => {
    await new Promise(resolve => setTimeout(resolve, 2000)); // 2 second delay
    res.json({ message: 'This was slow!' });
  });

  // Error endpoint for testing error logging
  app.get('/api/error', (req, res) => {
    throw new Error('Test error for logging');
  });

  // Error handling middleware (must be last)
  app.use(logStack.createErrorMiddleware());
  app.use((error, req, res, next) => {
    res.status(500).json({ error: 'Internal server error' });
  });

  const PORT = process.env.PORT || 3000;
  app.listen(PORT, () => {
    console.log(`๐Ÿš€ Express server running on port ${PORT}`);
    console.log('๐Ÿ“Š LogStack integration active');
    console.log('\n๐Ÿงช Test endpoints:');
    console.log(`   GET  http://localhost:${PORT}/api/users`);
    console.log(`   POST http://localhost:${PORT}/api/users`);
    console.log(`   POST http://localhost:${PORT}/api/login`);
    console.log(`   GET  http://localhost:${PORT}/api/slow`);
    console.log(`   GET  http://localhost:${PORT}/api/error`);
  });

  return app;
}

if (require.main === module) {
  createExpressApp().catch(console.error);
}

module.exports = { 
  ExpressLogStackIntegration, 
  createExpressApp 
};