npm package: @forgedock/fd-fastest-logger
Description: Structured logging utilities for FD-Fastest
Author: ForgeDock
Latest version: 0.1.0

# @fd-fastest/logger

Production-grade structured logging for the Fastest toolkit, powered by Pino.

## Features

- ✅ **Ultra-Fast** – Pino is one of the fastest loggers for Node.js
- ✅ **Structured Logging** – JSON output for easy parsing
- ✅ **Multiple Levels** – trace, debug, info, warn, error, fatal
- ✅ **Pretty Printing** – Human-readable output for development
- ✅ **Child Loggers** – Add context to specific modules
- ✅ **Custom Serializers** – Handle errors, requests, responses
- ✅ **Redaction** – Remove sensitive data automatically
- ✅ **TypeScript** – Full type safety

## Installation

```bash
pnpm add @fd-fastest/logger
```

## Quick Start

### Basic Usage

```typescript
import { createLogger } from '@fd-fastest/logger';

const logger = createLogger({ level: 'info' });

logger.info('Application started');
logger.error(new Error('Something went wrong'));
```

### Development vs Production

```typescript
// Development (pretty printing)
const devLogger = createLogger({
  level: 'debug',
  pretty: true,
});

// Production (JSON output)
const prodLogger = createLogger({
  level: 'info',
  pretty: false,
});
```

### Child Loggers with Context

```typescript
const logger = createLogger();

// Create child with module context
const moduleLogger = logger.child({ module: 'auth' });
moduleLogger.info('User logged in', { userId: '123' });

// Create child with request context
const requestLogger = logger.child({ requestId: 'abc-123' });
requestLogger.info('Processing request');
```

### Logging Errors

```typescript
import { NetworkError } from '@fd-fastest/errors';

try {
  await fetchData();
} catch (error) {
  // Automatically serializes error details
  logger.error(error as Error, 'Failed to fetch data');
}
```

### File Output

```typescript
const logger = createLogger({
  destination: {
    type: 'file',
    path: './logs/app.log',
    sync: false,
  },
});
```

### Multiple Outputs

```typescript
import {
  createLogger,
  createProductionMultiTransport,
} from '@fd-fastest/logger';

const logger = createLogger({
  pinoOptions: {
    transport: createProductionMultiTransport('./logs'),
  },
});
```

## API Reference

### createLogger(options)

Create a new logger instance.

```typescript
interface LoggerOptions {
  name?: string; // Logger name
  level?: LogLevel; // Min log level (default: 'info')
  pretty?: boolean; // Pretty print (default: dev mode)
  base?: Record<string, unknown>; // Base fields
  serializers?: Record<string, (value: unknown) => unknown>; // Custom serializers
  redact?: string[]; // Fields to redact
  destination?:
    | { type: 'stdout' | 'stderr'; sync?: boolean }
    | { type: 'file'; path?: string; sync?: boolean; mkdir?: boolean }
    | {
        type: 'multistream';
        targets: TransportConfig['targets'];
        dedupe?: boolean;
      };
  pinoOptions?: Partial<PinoLoggerOptions>; // Native pino overrides
}
```

### Log Levels

```typescript
logger.trace('Detailed debugging'); // Level 10
logger.debug('Debug information'); // Level 20
logger.info('General information'); // Level 30
logger.warn('Warning message'); // Level 40
logger.error('Error occurred'); // Level 50
logger.fatal('Fatal error'); // Level 60
```

### Logging Patterns

```typescript
// String message
logger.info('User logged in');

// With context object
logger.info({ userId: '123', action: 'login' }, 'User logged in');

// Error logging
logger.error(error, 'Operation failed');

// Performance timing
logger.info({ timing: { start: t0, end: t1 } }, 'Operation completed');
```

### Serializers

Custom serializers transform objects before logging:

```typescript
import {
  errorSerializer,
  requestSerializer,
  responseSerializer,
} from '@fd-fastest/logger';

const logger = createLogger({
  serializers: {
    error: errorSerializer, // Errors with full details
    req: requestSerializer, // HTTP requests (redacted)
    res: responseSerializer, // HTTP responses
    custom: (value) => value,
  },
});
```

### Redaction

Remove sensitive data from logs:

```typescript
const logger = createLogger({
  redact: [
    'password',
    'apiKey',
    'creditCard',
    'req.headers.authorization',
    'req.headers.cookie',
  ],
});

logger.info({
  username: 'john',
  password: 'secret123', // Will be removed
  apiKey: 'key456', // Will be removed
});
```

## Best Practices

### 1. Use Appropriate Log Levels

```typescript
logger.trace('Entering function', { args }); // Very detailed
logger.debug('Processing step', { step }); // Debugging
logger.info('User action', { userId }); // General info
logger.warn('Slow query', { duration }); // Warnings
logger.error(error, 'Operation failed'); // Errors
logger.fatal(error, 'System crash'); // Fatal errors
```

### 2. Add Context with Child Loggers

```typescript
// ❌ Bad: Repeating context
logger.info({ module: 'auth', userId: '123' }, 'Started');
logger.info({ module: 'auth', userId: '123' }, 'Completed');

// ✅ Good: Child logger with context
const authLogger = logger.child({ module: 'auth', userId: '123' });
authLogger.info('Started');
authLogger.info('Completed');
```

### 3. Log Objects, Not Strings

```typescript
// ❌ Bad: String concatenation
logger.info(`User ${userId} logged in at ${timestamp}`);

// ✅ Good: Structured data
logger.info({ userId, timestamp }, 'User logged in');
```

### 4. Use Serializers for Complex Objects

```typescript
// ❌ Bad: Manual serialization
logger.error(
  {
    errorMessage: error.message,
    errorStack: error.stack,
  },
  'Error occurred'
);

// ✅ Good: Let serializer handle it
logger.error(error, 'Error occurred');
```

### 5. Performance Logging

```typescript
const start = Date.now();

try {
  await operation();
  logger.info(
    { duration: Date.now() - start },
    'Operation completed successfully'
  );
} catch (error) {
  logger.error(
    { err: error as Error, duration: Date.now() - start },
    'Operation failed'
  );
}
```

## Production Configuration

### Recommended Setup

```typescript
import {
  createLogger,
  createProductionMultiTransport,
  type LogLevel,
} from '@fd-fastest/logger';

export const logger = createLogger({
  name: 'fastest-cli',
  level: (process.env.LOG_LEVEL as LogLevel) || 'info',
  pretty: process.env.NODE_ENV === 'development',
  base: {
    env: process.env.NODE_ENV,
    version: process.env.APP_VERSION,
  },
  redact: [
    'password',
    'apiKey',
    'token',
    '*.password',
    '*.apiKey',
    'req.headers.authorization',
    'req.headers.cookie',
  ],
  pinoOptions:
    process.env.NODE_ENV === 'production'
      ? {
          transport: createProductionMultiTransport('./logs'),
        }
      : undefined,
});
```

### Environment Variables

```bash
# Set log level
export LOG_LEVEL=debug

# Enable pretty printing
export NODE_ENV=development
```

## Performance

Pino is designed for performance:

- **Minimal overhead**: ~10-20% slower than console.log
- **Asynchronous**: Non-blocking I/O by default
- **Worker threads**: Pretty printing in separate thread
- **JSON.stringify optimization**: Custom serialization

```typescript
// Benchmark results (operations/sec)
console.log:   ~200,000
logger.info:   ~180,000  // Structured output with minimal overhead
```

## License

MIT