@plyaz/logger
v1.4.1
Published
Standardized logging infrastructure for Plyaz platform. Supports structured JSON logging, multiple transports, correlation IDs, and sensitive data redaction across all services.
Keywords
Readme
@plyaz/logger
Standardized logging infrastructure for the Plyaz platform. Provides structured JSON logging, multiple transports, correlation IDs, and sensitive data redaction across all services - supporting frontend, backend, and blockchain environments.
Overview
The @plyaz/logger package provides standardized logging capabilities across all services within the Plyaz platform. It ensures consistent log formatting, severity levels, and transport mechanisms, facilitating easier log aggregation, analysis, and troubleshooting across our microservices backend architecture and modular frontend applications.
Note: This package is designed as a shared package that works across frontend and backend contexts, with platform-specific implementations where necessary. It integrates seamlessly with the @plyaz/* ecosystem of shared packages.
Features
- Structured JSON Logging: Machine-readable log formats for easy parsing and analysis
- Multiple Transports: Console, file, cloud, localStorage, and remote logging support
- Cross-Platform Support: Works in Node.js, browsers, and blockchain environments
- Correlation IDs: Automatic tracking of requests across service boundaries
- Sensitive Data Redaction: Built-in PII and sensitive information masking
- Framework Integration: Ready-to-use integrations for NestJS, React, and Next.js
- Performance Optimized: Async logging, batching, and sampling capabilities
- TypeScript Support: Full type safety and IntelliSense
Installation
pnpm add @plyaz/loggerDevelopment
Prerequisites
- Node.js >= 22.4.0
- pnpm >= 8.0.0
Setup
# Clone the repository
git clone https://github.com/Plyaz-Official/logger.git
cd logger
# Install dependencies
pnpm install
# Start development (watch mode)
pnpm devAvailable Scripts
# Development
pnpm dev # Start development with watch mode (alias: pnpm build:watch)
pnpm build:watch # Watch files and rebuild on changes
# Building
pnpm build # Full build (clean + JS + TypeScript declarations)
pnpm build:js # Build JavaScript bundles with tsup
pnpm build:types # Generate TypeScript declaration files
pnpm clean # Remove dist directory
# Testing
pnpm test # Run all tests once
pnpm test:watch # Run tests in watch mode
pnpm test:coverage # Run tests with coverage report
pnpm test:ui # Open Vitest UI for interactive testing
pnpm test:ci # Run tests in CI environment
# Code Quality
pnpm lint # Check code with ESLint
pnpm lint:fix # Auto-fix ESLint issues
pnpm format # Format code with Prettier
pnpm format:check # Check if code is formatted correctly
pnpm type:check # Type check with TypeScript (no emit)
# Security & Auditing
pnpm audit # Basic security audit
pnpm audit:moderate # Check for moderate+ vulnerabilities
pnpm audit:high # Check for high+ vulnerabilities
pnpm audit:critical # Check only critical vulnerabilities
pnpm audit:fix # Auto-fix vulnerabilities where possible
pnpm audit:enhanced # Enhanced audit with audit-ci
pnpm security:check # Full security check (moderate + audit-ci)
# Publishing
pnpm prepublishOnly # Runs build, test, and lint before publishingPackage Structure
@plyaz/logger/
├── src/
│ ├── core/ # Platform-agnostic core
│ │ ├── logger.ts # Core logger implementation
│ │ ├── levels.ts # Log levels
│ │ └── types.ts # Shared types
│ ├── browser/ # Browser-specific code
│ │ ├── transports/ # Browser transports
│ │ └── react/ # React integration
│ ├── node/ # Node.js specific code
│ │ ├── transports/ # Node transports
│ │ └── nestjs/ # NestJS integration
│ ├── blockchain/ # Blockchain specific code
│ ├── formatters/ # Log formatters
│ ├── utils/ # Helper utilities
│ └── index.ts # Main entry with environment detectionQuick Start
Backend (NestJS)
Module Setup
import { Module } from '@nestjs/common';
import { LoggerModule } from '@plyaz/logger/node/nestjs';
@Module({
imports: [
LoggerModule.forRoot({
service: 'user-service',
version: '1.0.0',
environment: process.env.NODE_ENV,
level: process.env.LOG_LEVEL || 'info',
transports: ['console', 'file'],
redactFields: ['password', 'token', 'creditCard'],
isGlobal: true
})
]
})
export class AppModule {}Using in a Service
import { Injectable } from '@nestjs/common';
import { Logger } from '@plyaz/logger';
@Injectable()
export class UserService {
private readonly logger: Logger;
constructor(logger: Logger) {
this.logger = logger.createChild({ component: UserService.name });
}
async createUser(userData: CreateUserDto): Promise<User> {
this.logger.debug('Creating new user', { email: userData.email });
try {
const user = await this.userRepository.create(userData);
this.logger.info('User created successfully', {
userId: user.id,
verification: user.isVerified ? 'verified' : 'pending'
});
return user;
} catch (error) {
this.logger.error('Failed to create user', {
error: error.message,
stack: error.stack,
email: userData.email
});
throw error;
}
}
}With Request Interceptor
import { Controller, Get, Param, UseInterceptors } from '@nestjs/common';
import { Logger, LoggingInterceptor } from '@plyaz/logger/node/nestjs';
@Controller('users')
@UseInterceptors(LoggingInterceptor) // Adds request logging with correlation IDs
export class UsersController {
private readonly logger: Logger;
constructor(logger: Logger, private readonly userService: UserService) {
this.logger = logger.createChild({ component: UsersController.name });
}
@Get(':id')
async getUserById(@Param('id') id: string) {
return this.userService.getUserById(id);
}
}Frontend (React/Next.js)
App Router Setup
'use client';
import { LoggerProvider } from '@plyaz/logger/browser/react';
import { setupErrorLogging } from '@plyaz/logger/browser/react/nextjs';
import { ReactNode, useEffect } from 'react';
export function Providers({ children }: { children: ReactNode }) {
useEffect(() => {
setupErrorLogging();
}, []);
return (
<LoggerProvider options={{
service: 'web-client',
environment: process.env.NODE_ENV,
level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
redactFields: ['password', 'token']
}}>
{children}
</LoggerProvider>
);
}Using in Components
'use client';
import { useLogger } from '@plyaz/logger/browser/react';
import { useState } from 'react';
export function ProfileForm({ userId }: { userId: string }) {
const logger = useLogger('ProfileForm');
const [formData, setFormData] = useState({});
const handleSubmit = async (e) => {
e.preventDefault();
logger.info('Submitting profile update', { userId });
try {
await updateProfile(userId, formData);
logger.info('Profile updated successfully');
} catch (error) {
logger.error('Failed to update profile', {
error: error.message,
userId
});
}
};
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button type="submit">Save</button>
</form>
);
}Next.js Middleware
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { withLogging } from '@plyaz/logger/browser/react/nextjs';
export function middleware(request: NextRequest) {
const response = NextResponse.next();
return response;
}
export default withLogging(middleware);Blockchain Integration
import { Injectable } from '@nestjs/common';
import { BlockchainLogger } from '@plyaz/logger/blockchain';
@Injectable()
export class Web3Service {
private readonly logger: BlockchainLogger;
constructor() {
this.logger = new BlockchainLogger({
service: 'web3-service',
environment: process.env.NODE_ENV
});
}
async sendTransaction(to: string, amount: string) {
try {
const tx = await contract.methods.transfer(to, amount).send();
this.logger.logTransaction(tx.hash, {
from: tx.from,
to,
amount,
contract: contractAddress
});
this.logger.logGasUsage(tx.hash, tx.gasUsed, tx.effectiveGasPrice);
return tx.hash;
} catch (error) {
this.logger.error('Transaction failed', { error: error.message });
throw error;
}
}
}Log Structure
All logs follow a standardized JSON structure:
{
"timestamp": "2025-03-25T10:23:42.315Z",
"level": "info",
"message": "User registration successful",
"service": "user-service",
"environment": "production",
"correlationId": "c7d2fbe3-3a3a-4e1e-8e4d-12c98765d234",
"requestId": "req-5c91e0b2-a6dc-487c-b5ec-2f79c4204def",
"context": {
"userId": "usr-123456",
"action": "registration",
"duration": 235
},
"labels": {
"version": "1.0.0",
"instance": "user-service-prod-7f84d9b68b-z92vn"
}
}Configuration
Full Configuration Options
{
// Basic identification
service: 'user-service', // Service name
version: '1.0.0', // Service version
environment: 'production', // Environment
// Log level configuration
level: 'info', // Default level
levels: { // Environment-specific levels
development: 'debug',
test: 'debug',
production: 'info'
},
// Transports configuration
transports: ['console', 'file'], // Enabled transports
console: { // Console transport config
pretty: true, // Pretty print in dev
colors: true // Colorized output
},
file: { // File transport config
path: 'logs/',
filename: 'app-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxFiles: '14d'
},
// Browser-specific options
browser: {
remoteLogging: { // Send logs to backend
endpoint: '/api/logs',
batchSize: 10,
flushInterval: 5000 // ms
},
localStorage: { // Store logs in localStorage
enabled: true,
key: 'app_logs',
maxEntries: 100
}
},
// Security and redaction
redactFields: ['password', 'token', 'creditCard'],
redactionText: '[REDACTED]',
// Correlation
enableCorrelationId: true,
correlationIdHeader: 'x-correlation-id',
// Performance
asyncLogging: true,
logSampling: {
debug: 0.1, // Sample 10% of debug logs
info: 1.0 // Log all info and above
}
}Transport Options
Node.js Transports
- Console: Colored, formatted output for development
- File: Rotating file logs with configurable retention
- Cloud: AWS CloudWatch, Google Cloud Logging integration
Browser Transports
- Console: Pretty-printed logs with formatting
- Remote: Send logs to backend API endpoint
- LocalStorage: Offline log storage for debugging
Security Features
Automatic Redaction
logger.info('User authentication', {
email: '[email protected]',
password: 'secret123', // Automatically redacted
token: 'Bearer abc123', // Automatically redacted
creditCard: '4111111111111111' // Automatically redacted
});Configurable Redaction Patterns
{
redactFields: ['password', 'token', 'apiKey', 'secret'],
redactionText: '[REDACTED]',
customPatterns: [
/Bearer\s+[^\s]+/gi,
/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g // Credit cards
]
}Performance Features
Log Sampling
{
logSampling: {
debug: 0.1, // Log only 10% of debug messages
info: 1.0, // Log all info messages
warn: 1.0,
error: 1.0
}
}Batching (Browser)
{
browser: {
remoteLogging: {
batchSize: 10, // Batch 10 logs together
flushInterval: 5000, // Send every 5 seconds
maxRetries: 3
}
}
}Best Practices
Log Levels
- debug: Detailed information for debugging
- info: General operational information
- warn: Potential issues that don't cause failure
- error: Errors that prevent operations from completing
- fatal: Critical errors requiring immediate attention
Message Guidelines
// Good: Specific and actionable
logger.info('User registration completed', { userId, email, duration });
// Bad: Vague and unhelpful
logger.info('Something happened');
// Good: Includes context
logger.error('Database connection failed', {
host: dbHost,
error: error.message,
retryCount
});
// Bad: Missing context
logger.error('Error');Performance Considerations
- Use appropriate log levels
- Avoid logging in tight loops
- Use sampling for high-volume debug logs
- Batch logs when possible (browser)
- Use child loggers for component context
Platform Architecture Context
The logger is a critical component of the Plyaz platform's shared package ecosystem:
Backend Architecture
- Microservices: Each NestJS microservice uses the logger for service-specific logging contexts
- API Gateway: Centralized logging point with correlation ID propagation
- Event-Driven: Event correlation tracking across asynchronous service communication
- Distributed Tracing: Correlation IDs enable request tracking across service boundaries
Frontend Architecture
- Multiple Apps: Supports web app, admin panel, landing pages, and micro apps
- React/Next.js: Deep integration with React Context and Next.js middleware
- State Management: Logs state changes in Zustand stores
- API Client: Tracks all API calls with React Query integration
Integration with Other Plyaz Packages
| Package | Integration | Purpose | |---------|------------|---------| | @plyaz/config | Configuration source | Reads LOG_LEVEL, SERVICE_NAME, environment settings | | @plyaz/monitoring | Data consumer | Logs feed into monitoring metrics and alerts | | @plyaz/events | Correlation | Event publishing includes logger correlation IDs | | @plyaz/errors | Error formatting | Structured error logging with stack traces | | @plyaz/auth | Context enrichment | Adds user/session context to logs | | @plyaz/api | Request tracking | Logs API calls, responses, and errors | | @plyaz/web3 | Transaction logging | Specialized blockchain transaction logging | | @plyaz/common | NestJS utilities | Provides logging interceptors and filters | | @plyaz/types | Type definitions | Shared LogEntry, LogLevel interfaces |
API Reference
Core Methods
createLogger(options): Create a new logger instancelogger.debug(message, context?): Log debug messagelogger.info(message, context?): Log info messagelogger.warn(message, context?): Log warninglogger.error(message, context?): Log errorlogger.fatal(message, context?): Log fatal errorlogger.createChild(context): Create child logger with context
React Hooks
useLogger(component): Get logger instance in React componentLoggerProvider: React context provider for logger
NestJS
LoggerModule.forRoot(options): Configure logger moduleLoggingInterceptor: Request logging interceptor@InjectLogger(): Inject logger into services
Blockchain
BlockchainLogger: Specialized blockchain loggerlogTransaction(hash, details): Log transaction detailslogGasUsage(hash, used, price): Log gas consumption
Migration Guide
From console.log
// Before
console.log('User logged in:', userId);
console.error('Error:', error);
// After
logger.info('User logged in', { userId });
logger.error('Operation failed', { error });From Winston/Bunyan
// Before (Winston)
winston.log('info', 'User action', { user: userId });
// After
logger.info('User action', { userId });Contributing
This package is part of the Plyaz platform. Please follow the contribution guidelines in the main repository.
Resources
License
ISC © Plyaz
