Migration Guide

This guide helps you migrate from the old node-syslog package to the new modern implementation.

Overview

The new node-syslog is a complete rewrite with:

  • ✅ Modern TypeScript API with full IntelliSense
  • ✅ Fluent interface with method chaining
  • ✅ Better error handling and validation
  • ✅ Precompiled binaries for easy installation
  • ✅ Comprehensive test coverage
  • ❌ Breaking API changes (this guide helps)

Quick Reference

Old API New API Notes
require('node-syslog') import { Syslog } from 'node-syslog' ES modules
syslog.init() new Syslog() Constructor-based
syslog.log() logger.info/error/etc() Specific methods
Constants Facilities/Levels/Options Enum-based

Step-by-Step Migration

1. Update Import

Before:

const syslog = require('node-syslog');

After:

import { Syslog, SyslogFacility, SyslogLevel, SyslogOption } from 'node-syslog';
// or for convenience functions:
import { info, error, warning } from 'node-syslog';

2. Replace Initialization

Before:

syslog.init('my-app', syslog.LOG_PID | syslog.LOG_ODELAY, syslog.LOG_LOCAL0);

After:

const logger = new Syslog({
  ident: 'my-app',
  facility: SyslogFacility.LOG_LOCAL0,
  options: SyslogOption.LOG_PID | SyslogOption.LOG_ODELAY
});

3. Update Logging Calls

Before:

syslog.log(syslog.LOG_INFO, 'Application started');
syslog.log(syslog.LOG_ERR, 'Database connection failed');

After (Method 1 - Instance methods):

logger.info('Application started');
logger.error('Database connection failed');

After (Method 2 - Convenience functions):

import { info, error } from 'node-syslog';

info('Application started');
error('Database connection failed');

4. Update Constants

Before:

const facility = syslog.LOG_LOCAL0;
const level = syslog.LOG_INFO;
const options = syslog.LOG_PID;

After:

const facility = SyslogFacility.LOG_LOCAL0;
const level = SyslogLevel.LOG_INFO;
const options = SyslogOption.LOG_PID;

Complete Migration Examples

Example 1: Basic Web Server

Before:

const syslog = require('node-syslog');
const express = require('express');

syslog.init('web-server', syslog.LOG_PID, syslog.LOG_DAEMON);

const app = express();

app.use((req, res, next) => {
  syslog.log(syslog.LOG_INFO, `${req.method} ${req.url}`);
  next();
});

app.use((err, req, res, next) => {
  syslog.log(syslog.LOG_ERR, `Error: ${err.message}`);
  res.status(500).send('Internal Server Error');
});

app.listen(3000, () => {
  syslog.log(syslog.LOG_INFO, 'Server started on port 3000');
});

After:

import express from 'express';
import { Syslog, SyslogFacility, SyslogOption } from 'node-syslog';

const logger = new Syslog({
  ident: 'web-server',
  facility: SyslogFacility.LOG_DAEMON,
  options: SyslogOption.LOG_PID
});

const app = express();

app.use((req, res, next) => {
  logger.info(`${req.method} ${req.url}`);
  next();
});

app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
  logger.error('Request error', { 
    error: err.message,
    stack: err.stack,
    url: req.url,
    method: req.method
  });
  res.status(500).send('Internal Server Error');
});

app.listen(3000, () => {
  logger.info('Server started on port 3000');
});

Example 2: Database Service

Before:

const syslog = require('node-syslog');
const mysql = require('mysql');

syslog.init('db-service', syslog.LOG_PID | syslog.LOG_CONS, syslog.LOG_LOCAL1);

function query(sql, params, callback) {
  syslog.log(syslog.LOG_DEBUG, `Executing query: ${sql}`);
  
  mysql.query(sql, params, (err, results) => {
    if (err) {
      syslog.log(syslog.LOG_ERR, `Query failed: ${err.message}`);
      return callback(err);
    }
    
    syslog.log(syslog.LOG_INFO, `Query returned ${results.length} rows`);
    callback(null, results);
  });
}

After:

import mysql from 'mysql';
import { Syslog, SyslogFacility, SyslogOption } from 'node-syslog';

const logger = new Syslog({
  ident: 'db-service',
  facility: SyslogFacility.LOG_LOCAL1,
  options: SyslogOption.LOG_PID | SyslogOption.LOG_CONS
});

interface QueryResult {
  [key: string]: any;
}

function query(sql: string, params: any[]): Promise<QueryResult[]> {
  return new Promise((resolve, reject) => {
    logger.debug('Executing query', { sql, params });
    
    mysql.query(sql, params, (err: Error, results: QueryResult[]) => {
      if (err) {
        logger.error('Query failed', { 
          error: err.message,
          sql,
          params 
        });
        return reject(err);
      }
      
      logger.info('Query completed', { 
        rowCount: results.length,
        sql 
      });
      resolve(results);
    });
  });
}

Example 3: Background Worker

Before:

const syslog = require('node-syslog');
const { Worker } = require('worker_threads');

syslog.init('worker', syslog.LOG_PID, syslog.LOG_LOCAL2);

function processJob(job) {
  syslog.log(syslog.LOG_INFO, `Processing job ${job.id}`);
  
  try {
    // Process job...
    syslog.log(syslog.LOG_NOTICE, `Job ${job.id} completed successfully`);
  } catch (error) {
    syslog.log(syslog.LOG_CRIT, `Job ${job.id} failed: ${error.message}`);
  }
}

After:

import { Worker } from 'worker_threads';
import { Syslog, SyslogFacility } from 'node-syslog';

const logger = new Syslog({
  ident: 'worker',
  facility: SyslogFacility.LOG_LOCAL2
});

interface Job {
  id: string;
  type: string;
  data: any;
}

async function processJob(job: Job): Promise<void> {
  logger.info('Processing job', { 
    jobId: job.id,
    jobType: job.type 
  });
  
  try {
    // Process job...
    await performJobWork(job);
    
    logger.notice('Job completed successfully', { 
      jobId: job.id 
    });
  } catch (error) {
    logger.critical('Job failed', { 
      jobId: job.id,
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined
    });
    throw error;
  }
}

New Features You Should Use

1. Context Logging

New capability:

logger.error('User authentication failed', {
  userId: 123,
  ip: '192.168.1.100',
  userAgent: 'Mozilla/5.0...',
  timestamp: new Date().toISOString()
});

2. Method Chaining

New capability:

logger
  .debug('Starting request')
  .info('Processing data')
  .warning('Rate limit approaching')
  .error('Request failed');

3. TypeScript Support

New capability:

// Full IntelliSense support
const logger = new Syslog({
  ident: 'my-app',
  facility: SyslogFacility.LOG_LOCAL0, // Auto-completion
  options: SyslogOption.LOG_PID | SyslogOption.LOG_CONS  // Type-safe
});

logger.info('Message'); // Method signatures with types

Breaking Changes Summary

Removed Features

  • No more global state (each instance is independent)
  • No more syslog.log() with level constants
  • No more CommonJS require (use ES imports)

Added Features

  • Fluent interface with method chaining
  • Context object support in all logging methods
  • TypeScript definitions and IntelliSense
  • Better error messages and validation
  • Precompiled binaries

Changed Behavior

  • Constructor-based initialization instead of global init
  • Specific methods for each log level
  • Enum-based constants instead of plain numbers

Testing Your Migration

1. Install Side-by-Side

# Keep old version for comparison
npm install node-syslog@1
npm install node-syslog@2

2. Create Compatibility Layer

// compatibility.ts
import { Syslog, SyslogFacility, SyslogLevel, SyslogOption } from 'node-syslog';

let globalLogger: Syslog | null = null;

export const legacy = {
  init: (ident: string, options: number, facility: number) => {
    globalLogger = new Syslog({ ident, facility, options });
  },
  
  log: (priority: number, message: string) => {
    if (!globalLogger) throw new Error('Syslog not initialized');
    
    switch (priority) {
      case SyslogLevel.LOG_EMERG: globalLogger.emergency(message); break;
      case SyslogLevel.LOG_ALERT: globalLogger.alert(message); break;
      case SyslogLevel.LOG_CRIT: globalLogger.critical(message); break;
      case SyslogLevel.LOG_ERR: globalLogger.error(message); break;
      case SyslogLevel.LOG_WARNING: globalLogger.warning(message); break;
      case SyslogLevel.LOG_NOTICE: globalLogger.notice(message); break;
      case SyslogLevel.LOG_INFO: globalLogger.info(message); break;
      case SyslogLevel.LOG_DEBUG: globalLogger.debug(message); break;
    }
  }
};

3. Gradual Migration

// Phase 1: Use compatibility layer
import { legacy } from './compatibility';
legacy.init('my-app', SyslogOption.LOG_PID, SyslogFacility.LOG_USER);
legacy.log(SyslogLevel.LOG_INFO, 'Still using old API');

// Phase 2: Mix old and new
import { Syslog } from 'node-syslog';
const logger = new Syslog({ ident: 'my-app' });
logger.info('Using new API');

// Phase 3: Full migration
// Remove compatibility layer and old imports

Common Migration Issues

Issue 1: Missing Global State

Problem: Old code relied on global syslog state

// Old code - multiple files sharing global state
// file1.js
syslog.init('app', syslog.LOG_PID, syslog.LOG_USER);

// file2.js  
syslog.log(syslog.LOG_INFO, 'Message'); // Uses global state

Solution: Pass logger instance or use convenience functions

// file1.ts
import { createSyslog } from 'node-syslog';
export const logger = createSyslog({ ident: 'app' });

// file2.ts
import { logger } from './file1';
logger.info('Message');

// Or use convenience functions:
import { info } from 'node-syslog';
info('Message'); // Uses default logger

Issue 2: Different Error Handling

Problem: New API throws different errors

// Old code
try {
  syslog.log(syslog.LOG_INFO, message);
} catch (e) {
  // Handle old error format
}

Solution: Update error handling

// New code
try {
  logger.info(message);
} catch (error) {
  if (error instanceof Error) {
    // Handle new error format with better messages
    console.error('Syslog error:', error.message);
  }
}

Need Help?