npm.io
3.6.3 • Published 1 week ago

@mdaemon/logfile

Licence
LGPL-2.1
Version
3.6.3
Deps
0
Size
68 kB
Vulns
0
Weekly
0
Stars
2

Dynamic JSON Badge Static Badge install size Dynamic JSON Badge Node.js CI

@mdaemon/logfile, A node only async logging utility

Not applicable to a browser context.

Install

$ npm install @mdaemon/logfile --save

Node CommonJS

    const LogFile = require("@mdaemon/logfile");

Node Modules

    import LogFile from "@mdaemon/logfile";

LogFile

LogFile Initialization Options

  /* default LogFileOptions 
   * logLevel: 1 (INFO)
   * dir: "./logs"
   * fileFormat: "log-%DATE%.log"
   * logToConsole: false
   * rollover: true
   * maxFileSize: 104857600 (100 MB)
   * registerProcessHandlers: false
   * onError: undefined
   * logStr: "%DATE% %TIME% | %LEVEL% | %MESSAGE%";
   * startLog: "-----------------------------------------\n" +
   *           "------- Log Started: %DATETIME%\n" +
   *           "-----------------------------------------\n";
   *    
   * endLog: "-----------------------------------------\n" +
   *         "------- Log Ended: %DATETIME%\n" +
   *         "-----------------------------------------\n";
  */
LogFile Example
  const { INFO, ERROR, WARNING, CRITICAL, DEBUG } = LogFile;
  const logFile = new LogFile({ logLevel: DEBUG });

  logFile.start();

  logFile.log("There was an error", ERROR);

  logFile.stop();
  /* file result 
  -----------------------------------------
  ------- Log Started: Fri, 08 Mar 2024 16:07:19 GMT
  -----------------------------------------
  2024-03-08 16:07:19 | ERROR | There was an error
  -----------------------------------------
  ------- Log Ended: Fri, 08 Mar 2024 16:07:19 GMT
  -----------------------------------------
  */
LogFile Options
  // set the log str
  logFile.setLogStr("%DATE% %TIME% | %LEVEL% | %MESSAGE%");

  // set the log dir
  logFile.setLogDir("./logs");

  // set the rollover boolean
  logFile.setRollover(true);

  // set the log level
  logFile.setLogLevel(DEBUG);

  // set the file name format
  logFile.setFileFormat("log-%DATE%.log");

  // set the log to console boolean
  logFile.setLogToConsole(true);

  // set the start log string
  logFile.setStartLog("-----------------------------------------\n");

  // set the end log string
  logFile.setEndLog("-----------------------------------------\n");

  // set whether timestamps use server local time (true, default) or UTC (false)
  logFile.setUseServerTime(true);

  // log help to the console
  logFile.getHelp();

  // log with an explicit level (defaults to DEBUG when omitted)
  logFile.log("This is an error log", LogFile.ERROR);

  // log to info
  logFile.info("This is an info log");

  // log to warning
  logFile.warning("This is a warning log");

  // warn is an alias for warning
  logFile.warn("This is a warn log");

  // log to error
  logFile.error("This is an error log");

  // log to critical
  logFile.critical("This is a critical log");

  // log to debug
  logFile.debug("This is a debug log");

  // force synchronous flush to disk
  logFile.flushSync();
Log File Rollover

The logger supports two types of automatic file rollover:

Date-based Rollover (when rollover: true):

  • Automatically creates a new log file when the date changes
  • File names use the fileFormat pattern with %DATE% replaced by the current date
  • Example: log-2024-01-01.log, log-2024-01-02.log, etc.

Size-based Rollover (controlled by maxFileSize):

  • Automatically creates a new log file when the current file exceeds maxFileSize (default: 100 MB)
  • New files are created with an incremental numeric suffix
  • Example: If log-2024-01-01.log exceeds the max size:
    • First rollover creates: log-2024-01-01-1.log
    • Second rollover creates: log-2024-01-01-2.log
    • And so on...
  • The suffix counter resets to 0 when a date-based rollover occurs

Combined Behavior:

  • Both rollover types work together seamlessly
  • Date changes always create a new base file (resetting the size suffix)
  • Within a single day, size-based rollovers create numbered variants
  • Each new file (date or size-based) starts with the startLog message
  • Files being closed receive the endLog message
// Example: Create a logger with a 50 MB max file size
const logFile = new LogFile({ 
  maxFileSize: 52428800, // 50 MB in bytes
  fileFormat: "app-%DATE%.log"
});

// This will create files like:
// app-2024-01-01.log (up to 50 MB)
// app-2024-01-01-1.log (up to 50 MB)
// app-2024-01-01-2.log (up to 50 MB)
// app-2024-01-02.log (new day, suffix resets)
LogFile Methods
Log Levels

Available as static constants on the LogFile class:

  • LogFile.DEBUG = 0
  • LogFile.INFO = 1
  • LogFile.WARNING = 2
  • LogFile.ERROR = 3
  • LogFile.CRITICAL = 4

Messages below the configured logLevel are not written.

Configuration Methods
  • setLogStr(format) / getLogStr() - Set/get the log entry format string
  • setLogDir(path) / getLogDir() - Set/get the directory for log files
  • setRollover(boolean) / getRollover() - Enable/disable daily log file rollover
  • setLogLevel(level) / getLogLevel() - Set/get the minimum log level
  • setFileFormat(format) / getFileFormat() - Set/get the log filename format
  • setLogToConsole(bool) / getLogToConsole() - Enable/disable console output
  • setStartLog(string) / getStartLog() - Set/get the log file start string
  • setEndLog(string) / getEndLog() - Set/get the log file end string
  • setUseServerTime(bool) - Use server local time (default: true) or UTC for timestamps
Constructor Options
  • logLevel - Minimum log level (default: LogFile.INFO)
  • dir - Log file directory (default: "./logs")
  • fileFormat - Filename format (default: "log-%DATE%.log")
  • logToConsole - Also log to console (default: false)
  • rollover - Enable date-based rollover (default: true)
  • maxFileSize - Max file size in bytes before size-based rollover (default: 104857600)
  • logStr - Log entry format string
  • startLog - Message written when log file starts
  • endLog - Message written when log file ends
  • registerProcessHandlers - Register SIGINT/SIGTERM/exit handlers (default: false)
  • onError - Callback invoked on I/O errors: (error: Error) => void
Logging Methods
  • log(message, level) - Log a message at the given level (defaults to LogFile.DEBUG)
  • debug(...args) - Log a debug message
  • info(...args) - Log an info message
  • warning(...args) - Log a warning message
  • warn(...args) - Alias for warning
  • error(...args) - Log an error message
  • critical(...args) - Log a critical message (automatically flushes to disk)

All logging methods return true on success and false on failure. The level-specific methods accept multiple arguments; non-string arguments are stringified and joined with spaces.

Utility Methods
  • getHelp() - Display help information
  • flushSync() - Force immediate synchronous write of buffered logs to disk
  • file() - Get the path to the current log file
  • lastFile() - Get the path to the previous log file
  • start() - Initialize the logger and set up shutdown handlers
  • stop() - Stop the logger, flush remaining logs, and clean up resources
Forced Shutdown Protection

The logger can optionally handle various termination scenarios to ensure logs are not lost. Set registerProcessHandlers: true to enable:

const logFile = new LogFile({ 
  logLevel: LogFile.DEBUG,
  registerProcessHandlers: true 
});
  • Registers handlers for exit, SIGINT, and SIGTERM signals to flush logs
  • Automatically logs and flushes uncaught exceptions before termination
  • Handlers are removed when stop() is called, preventing listener leaks
  • Critical log messages are always immediately flushed to disk (regardless of this option)

Testing

The package includes a comprehensive testing setup that allows for testing the following formats:

  1. TypeScript source files (index.ts) before building
  2. CommonJS output (logfile.cjs) after building

Running Tests

# Test TypeScript source directly
npm run test:source

# Test CommonJS output
npm run test:cjs

# Run all tests (source, build CommonJS, then test each)
npm run test:all

The testing system uses a test helper that dynamically imports the appropriate module format based on environment variables, allowing the same test suite to verify all formats.

// Example of how to use the test helper in tests
import { getLogFile } from './test-helper';

// Wait for the LogFile class to be dynamically loaded
const LogFile = await getLogFile();
const logFile = new LogFile({ logLevel: LogFile.DEBUG });

Testing Challenges

Testing different module formats in Jest can be challenging. This project addresses these challenges by:

  1. Using different Jest configurations for different module formats
  2. Dynamically importing modules based on the test environment
  3. Properly handling imports and mocks

If you're extending the tests, be aware that different module formats may require special handling for imports, mocks, and configuration.

License

Published under the LGPL-2.1 license.

Published by
MDaemon Technologies, Ltd.
Simple Secure Email
https://www.mdaemon.com

Keywords