@heady/logger
v1.0.1
Published
  
Keywords
Readme
Structured CloudWatch Logger
A production-ready TypeScript logger wrapper around Winston, designed specifically for AWS CloudWatch Logs and CloudWatch Insights.
It enforces structured JSON logging while maintaining human-readable messages, ensuring your logs are easy to debug locally and easy to query in production.
🚀 Features
- Structured JSON: automatically formats logs for CloudWatch (no more JSON.stringify).
- Context Awareness: Automates [Class:Method] prefixes in messages.
- Metadata Support: persistent metadata (like requestId, userId) attached to every log.
- Error Optimization: Extracts error messages to the top level for easy sorting in CloudWatch Insights.
- Type Safety: Built with TypeScript.
📦 Installation
npm install @heady/logger
# or
yarn add @heady/logger🛠 Usage
1. Basic Usage
Initialize the logger with a Context (usually the Class name).
import { LogService } from '@heady/logger';
class UserService {
// 1. Initialize with Context Name
private logger = new LogService('UserService');
getUser(id: string) {
// 2. Log (Method, Message, Description, Data)
this.logger.info(
'getUser', // Method Name
'fetching user data', // Short Message
'checking cache first', // Detailed Description
{ id, cache: true } // Data Object (No JSON.stringify needed!)
);
}
}Output in Console (JSON):
{
"timestamp": "2023-10-27T10:00:00Z",
"level": "info",
"message": "[UserService:getUser] fetching user data",
"context": "UserService",
"method": "getUser",
"description": "checking cache first",
"data": { "id": "123", "cache": true }
}2. Using Metadata (Request Tracing)
Pass metadata (like requestId or userId) during initialization. It will be attached to every log line generated by that instance.
// Ideally done in your Controller or Middleware
const requestId = 'req-12345';
const userId = 'user-987';
const logger = new LogService('OrderController', { requestId, userId });
logger.info('createOrder', 'order received');
// The JSON log will automatically include "requestId": "req-12345"3. Error Handling
Pass the raw Error object as the last argument. The logger extracts the stack trace and lifts the error message to the top level for better visibility.
try {
await db.connect();
} catch (err) {
// Pass the raw error object
logger.error('connect', 'db connection failed', 'retrying...', err);
}4. Debug Logging
Debug logs are hidden by default. They only appear if the environment variable LOG_LEVEL is set to debug.
logger.debug('calc', 'loop iteration', null, { x: 10, y: 20 });⚙️ Configuration
Control the logger behavior using Environment Variables.
|Variable|Default|Description| |--------|-------|-----------| |LOG_LEVEL| info|Set to debug to see verbose logs. Set to error to reduce noise. SERVICE_NAME|my-app|Tags all logs with a service name for filtering in aggregated log streams.
Example (Local Run):
LOG_LEVEL=debug npm run start🔌 Framework Integration
AWS Lambda
import { LogService } from '@heady/logger';
export const handler = async (event) => {
const logger = new LogService('LambdaHandler', {
requestId: event.requestContext.requestId
});
logger.info('handler', 'processing event', null, event);
};NestJS Service
// logger.service.ts
import { Injectable, Scope } from '@nestjs/common';
import { LogService } from '@heady/logger';
@Injectable({ scope: Scope.TRANSIENT })
export class AppLogger extends LogService {
// You can extend or wrap the class easily
}📊 CloudWatch Insights Cheat Sheet
Since the logs are structured, you can run powerful queries in AWS CloudWatch Insights:
Find all errors in a specific class:
fields @timestamp, message, errorMessage, error.stack
| filter level = "error"
| filter context = "UserService"
| sort @timestamp descTrace a specific request ID:
fields @timestamp, message, method
| filter requestId = "req-12345"
| sort @timestamp ascLicense
MIT
