Skip to content

Logger Helper

Powerful, flexible logging built on Winston - supports multiple transports, log levels, hierarchical scopes, and high-frequency logging for performance-critical applications.

Quick Reference

FeatureDescription
Factory MethodLoggerFactory.getLogger(['scope1', 'scope2'])
Direct AccessLogger.get('scope')
Method Scopinglogger.for('methodName').info('message')
Log Levelserror, alert, emerg, warn, info, http, verbose, debug, silly
TransportsConsole (default), DailyRotateFile, UDP/Dgram
FormatsJSON (json), Pretty Text (text)
HF LoggerZero-allocation logging for HFT use cases

Common Methods

typescript
logger.info('message');                    // Informational
logger.error('message');                   // Error
logger.warn('message');                    // Warning
logger.debug('message');                   // Debug (requires DEBUG=true)
logger.for('methodName').info('message');  // Method-scoped logging

Getting a Logger Instance

typescript
import { LoggerFactory } from '@venizia/ignis-helpers';

const logger = LoggerFactory.getLogger(['MyService']);

logger.info('This is an informational message.');
logger.error('This is an error message.');

Using Logger.get() Directly

typescript
import { Logger } from '@venizia/ignis-helpers';

const logger = Logger.get('MyService');
logger.info('Direct logger access');

Logger Caching

Both methods use internal caching - the same scope always returns the same logger instance:

typescript
const logger1 = Logger.get('MyService');
const logger2 = Logger.get('MyService');
// logger1 === logger2 (same instance)

Method-Scoped Logging with .for()

The .for() method creates a sub-scoped logger for specific methods, making it easy to trace logs:

typescript
class UserService {
  private logger = LoggerFactory.getLogger(['UserService']);

  async createUser(data: CreateUserDto) {
    this.logger.for('createUser').info('Creating user: %j', data);
    // Output: [UserService-createUser] Creating user: {...}

    try {
      const user = await this.userRepo.create({ data });
      this.logger.for('createUser').info('User created: %s', user.id);
      return user;
    } catch (error) {
      this.logger.for('createUser').error('Failed to create user: %s', error);
      throw error;
    }
  }
}

Log Formats

The logger supports two output formats controlled by APP_ENV_LOGGER_FORMAT:

JSON Format

bash
APP_ENV_LOGGER_FORMAT=json

Output:

json
{"level":"info","message":"[UserService] User created","timestamp":"2024-01-11T10:30:00.000Z","label":"app"}

Pretty Text Format (Default)

bash
APP_ENV_LOGGER_FORMAT=text

Output:

2024-01-11T10:30:00.000Z [app] info: [UserService] User created

File Rotation Configuration

Configure file rotation through environment variables or programmatically:

Environment Variables

VariableDefaultDescription
APP_ENV_LOGGER_FILE_FREQUENCY1hRotation frequency
APP_ENV_LOGGER_FILE_MAX_SIZE100mMax file size before rotation
APP_ENV_LOGGER_FILE_MAX_FILES5dRetention period (days)
APP_ENV_LOGGER_FILE_DATE_PATTERNYYYYMMDD_HHDate pattern in filename
APP_ENV_LOGGER_FOLDER_PATH./Log files directory

Programmatic Configuration

typescript
import { defineCustomLogger, applicationLogFormatter } from '@venizia/ignis-helpers';

const customLogger = defineCustomLogger({
  loggerFormatter: applicationLogFormatter,
  transports: {
    info: {
      file: {
        prefix: 'my-app',
        folder: './logs',
        frequency: '24h',       // Rotate daily
        maxSize: '500m',        // 500MB max
        maxFiles: '30d',        // Keep 30 days
        datePattern: 'YYYYMMDD' // Daily pattern
      }
    },
    error: {
      file: {
        prefix: 'my-app-error',
        folder: './logs',
        maxFiles: '90d'         // Keep error logs longer
      }
    }
  }
});

High-Frequency Logger (HfLogger)

For performance-critical applications like HFT systems, use HfLogger which provides:

  • Zero allocation in hot path
  • Lock-free ring buffer (64K entries)
  • Sub-microsecond latency (~100-300ns)
  • Pre-encoded messages
  • Async background flushing

Basic Usage

typescript
import { HfLogger, HfLogFlusher } from '@venizia/ignis-helpers';

// At initialization time (once):
const logger = HfLogger.get('OrderEngine');
const MSG_ORDER_SENT = HfLogger.encodeMessage('Order sent');
const MSG_ORDER_FILLED = HfLogger.encodeMessage('Order filled');

// Start background flusher
const flusher = new HfLogFlusher();
flusher.start(100); // Flush every 100ms

// In hot path (~100-300ns, zero allocation):
logger.log('info', MSG_ORDER_SENT);
logger.log('info', MSG_ORDER_FILLED);

HfLogger API

MethodDescription
HfLogger.get(scope)Get/create a cached logger instance
HfLogger.encodeMessage(msg)Pre-encode a message (cached)
logger.log(level, msgBytes)Log to ring buffer (zero allocation)

HfLogFlusher API

MethodDescription
flusher.flush()Flush buffered entries to output
flusher.start(intervalMs)Start background flush loop

Performance Characteristics

MetricValue
Log latency~100-300 nanoseconds
Buffer size64K entries (16MB)
Entry size256 bytes fixed
AllocationZero in hot path

Environment Variables

Core Configuration

VariableDefaultDescription
DEBUGfalseEnable debug logging
APP_ENV_EXTRA_LOG_ENVS``Additional environments to enable debug
APP_ENV_LOGGER_FORMATtextOutput format (json or text)
APP_ENV_LOGGER_FOLDER_PATH./Log files directory

UDP Transport

VariableDescription
APP_ENV_LOGGER_DGRAM_HOSTUDP log aggregator host
APP_ENV_LOGGER_DGRAM_PORTUDP log aggregator port
APP_ENV_LOGGER_DGRAM_LABELLabel to identify log source
APP_ENV_LOGGER_DGRAM_LEVELSComma-separated levels to send via UDP

Example .env

bash
# Core
DEBUG=true
APP_ENV_LOGGER_FORMAT=json
APP_ENV_LOGGER_FOLDER_PATH=./app_data/logs

# File rotation
APP_ENV_LOGGER_FILE_FREQUENCY=24h
APP_ENV_LOGGER_FILE_MAX_SIZE=500m
APP_ENV_LOGGER_FILE_MAX_FILES=30d

# UDP transport
APP_ENV_LOGGER_DGRAM_HOST=127.0.0.1
APP_ENV_LOGGER_DGRAM_PORT=5000
APP_ENV_LOGGER_DGRAM_LABEL=my-app
APP_ENV_LOGGER_DGRAM_LEVELS=error,warn,info

Best Practices

1. Use Method-Scoped Logging

typescript
// Good - clear context
this.logger.for('createOrder').info('Processing order: %s', orderId);

// Less clear
this.logger.info('[createOrder] Processing order: %s', orderId);

2. Pre-encode HfLogger Messages

typescript
// Good - pre-encoded at init
const MSG_TICK = HfLogger.encodeMessage('Tick received');
logger.log('debug', MSG_TICK);

// Bad - encodes on every call
logger.log('debug', HfLogger.encodeMessage('Tick received'));

3. Use Appropriate Logger for Use Case

Use CaseLogger
General applicationLogger / LoggerFactory
High-frequency tradingHfLogger
Performance-critical pathsHfLogger
Debug/developmentLogger with DEBUG=true

See Also