logstack-zee
Version:
Complete Node.js logging solution with 6 integration methods, S3 bidirectional operations, advanced analytics, and multi-cloud storage support for enterprise-scale applications.
1,580 lines (1,254 loc) โข 44.3 kB
Markdown
# ๐ logstack
A comprehensive, production-ready Node.js + TypeScript package for managing hourly API logs processing and uploads with automated cron jobs, MongoDB, and multiple cloud storage providers.
## โจ Features
- **๐
Automated Job Management**: Daily job creation with 24 hourly slots per day
- **โฐ Cron-based Execution**: Hourly file processing and upload automation
- **๐ Smart Retry Logic**: Automatic retry of failed jobs with configurable limits
- **โ๏ธ Multi-Cloud Support**: AWS S3, Google Cloud Storage, Azure Blob Storage, and local storage
- **๐ API Request Logging**: Built-in middleware for Express.js API logging with custom collections
- **๐๏ธ Custom Collection Names**: Avoid database conflicts with configurable collection names
- **๐ Organized Output Directory**: Clean project structure with organized file storage
- **โก High-Performance Processing**: Batch processing and streaming for large datasets
- **๐ฏ TypeScript Support**: Full type safety and IntelliSense support
- **๐ Comprehensive Logging**: Winston-based logging with file and console output
- **โ
Input Validation**: Configuration validation with helpful error messages
- **๐งช Test Coverage**: Jest-based test suite with comprehensive examples and production testing
## ๐ Installation
```bash
npm install logstack
```
## ๐ Quick Start
```typescript
import { init, createDailyJobs } from "logstack";
// Initialize with your preferred configuration
await init({
dbUri: "mongodb://localhost:27017/cronlog",
uploadProvider: "s3", // 'local', 's3', 'gcs', 'azure'
fileFormat: "json",
retryAttempts: 3,
// ๐ Organized output directory (keeps project clean)
outputDirectory: "production-logs",
// ๐๏ธ Custom collection names (avoid database conflicts)
collections: {
jobsCollectionName: "myapp_jobs", // Instead of default "jobs"
logsCollectionName: "myapp_logs", // Instead of default "logs"
apiLogsCollectionName: "myapp_apilogs", // Instead of default "apilogs"
},
s3: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: "us-east-1",
bucket: "my-logs-bucket",
},
logging: {
level: "info",
enableConsole: true,
enableFile: true,
},
});
// Create daily jobs (automatically done via cron)
await createDailyJobs();
```
## ๐ง Configuration Options
### Storage Providers
#### AWS S3
```typescript
{
uploadProvider: "s3",
outputDirectory: "production-logs", // Organized S3 structure
collections: {
jobsCollectionName: "prod_jobs", // Avoid conflicts
logsCollectionName: "prod_logs"
},
s3: {
accessKeyId: "your-access-key-id",
secretAccessKey: "your-secret-access-key",
region: "us-east-1",
bucket: "your-bucket-name",
endpoint: "https://custom-s3-endpoint.com" // Optional for S3-compatible services
}
}
```
**๐งช Test AWS Setup:**
```bash
npm run test:aws # Basic AWS S3 testing
npm run test:aws-performance # Performance testing
npm run test:aws-regions # Multi-region testing
```
**๐ S3 File Structure:**
```
s3://your-bucket/
โโโ production-logs/2025-08-25/14-15.json
โโโ dev-logs/2025-08-25/14-15.json
โโโ organized-structure/
```
#### Google Cloud Storage
```typescript
{
uploadProvider: "gcs",
gcs: {
projectId: "your-gcp-project-id",
keyFilename: "./path/to/service-account-key.json", // or use credentials
bucket: "your-gcs-bucket-name"
}
}
```
#### Azure Blob Storage
```typescript
{
uploadProvider: "azure",
azure: {
connectionString: "DefaultEndpointsProtocol=https;AccountName=...",
containerName: "your-container-name"
}
}
```
#### Local Storage
```typescript
{
uploadProvider: "local"; // Files saved to local filesystem
}
```
### Complete Configuration Interface
```typescript
interface Config {
dbUri: string;
uploadProvider: "local" | "s3" | "gcs" | "azure";
fileFormat?: "json" | "csv" | "txt";
retryAttempts?: number;
dailyCron?: string; // Default: '0 0 * * *' (midnight)
hourlyCron?: string; // Default: '0 * * * *' (every hour)
timezone?: string; // Default: 'UTC'
// ๐ Organized output directory for clean project structure
outputDirectory?: string; // Default: "uploads"
// ๐๏ธ Custom collection names to avoid database conflicts
collections?: {
jobsCollectionName?: string; // Default: "jobs"
logsCollectionName?: string; // Default: "logs"
apiLogsCollectionName?: string; // Default: "apilogs"
};
// ๐ API Logs Configuration (for existing collections)
apiLogs?: {
existingCollection?: {
name: string; // Your existing collection name
timestampField: string; // Field to filter by time
requiredFields?: {
/* field mappings */
};
};
createNew?: {
collectionName?: string;
enableMiddleware?: boolean;
autoFields?: boolean;
};
};
logging?: {
level: "debug" | "info" | "warn" | "error";
enableConsole?: boolean;
enableFile?: boolean;
logFilePath?: string;
};
// Cloud storage configurations
s3?: {
/* AWS S3 config */
};
gcs?: {
/* Google Cloud config */
};
azure?: {
/* Azure Blob config */
};
}
```
### ๐ Organized Output Directory
Keep your project clean by organizing generated files in a dedicated directory:
```typescript
await init({
dbUri: "mongodb://localhost:27017/your-db",
uploadProvider: "local",
// Organize files in a dedicated directory
outputDirectory: "logs", // Files saved in logs/{date}/
// Before: Files created in project root: 2025-08-25/00-01.json
// After: Files created in: logs/2025-08-25/00-01.json
});
```
### ๐๏ธ Custom Collection Names
Avoid database conflicts by using custom collection names:```typescript
await init({
dbUri: "mongodb://localhost:27017/your-db",
uploadProvider: "local",
// Use custom collection names to prevent conflicts
collections: {
jobsCollectionName: "my_file_processing_jobs", // Instead of "jobs"
logsCollectionName: "my_file_processing_logs", // Instead of "logs"
},
});
````
This is especially useful when:
- Running multiple instances of the service
- Avoiding conflicts with existing collections
- Organizing collections with meaningful names
- Separating environments (dev/staging/prod)
## ๐ Complete Node.js Implementation
### ๐ฆ 1. Installation & Setup
```bash
# Install the package
npm install logstack
# Install required dependencies
npm install mongodb mongoose
npm install dotenv # For environment variables
# Optional: AWS SDK for S3
npm install aws-sdk
# Optional: Express.js for API middleware
npm install express @types/express
```
### ๐ง 2. Environment Configuration
Create a `.env` file in your project root:
```env
# Database Configuration
DB_URI=mongodb://localhost:27017/your-app-name
# AWS S3 Configuration (if using S3)
AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_REGION=us-east-1
S3_BUCKET=your-bucket-name
# Application Configuration
NODE_ENV=production
LOG_LEVEL=info
```
### ๐ป 3. Basic Implementation (CommonJS)
```javascript
// basic-setup.js
const { init, createDailyJobs, processSpecificHour } = require('logstack');
require('dotenv').config();
async function setupCronLogService() {
try {
// Basic configuration
const config = {
dbUri: process.env.DB_URI || 'mongodb://localhost:27017/myapp',
uploadProvider: 'local', // Start with local storage
fileFormat: 'json',
// Organized file structure
outputDirectory: 'api-logs',
// Custom collections to avoid conflicts
collections: {
jobsCollectionName: 'myapp_jobs',
logsCollectionName: 'myapp_logs',
apiLogsCollectionName: 'myapp_apilogs'
},
logging: {
level: 'info',
enableConsole: true,
enableFile: true
}
};
// Initialize the service
console.log('๐ Initializing logstack...');
await init(config);
console.log('โ
Service initialized successfully');
// Create daily jobs for today
const today = new Date().toISOString().split('T')[0];
const job = await createDailyJobs(today, config);
console.log(`๐
Created daily job with ${job.hours.length} hour slots`);
// Process specific hour (example)
const currentHour = new Date().getHours();
await processSpecificHour(today, currentHour, config);
console.log(`โก Processed hour ${currentHour}:00-${currentHour + 1}:00`);
} catch (error) {
console.error('โ Setup failed:', error);
process.exit(1);
}
}
// Run the setup
setupCronLogService();
```
### ๐ฏ 4. Advanced Implementation (ES Modules)
```javascript
// advanced-setup.mjs
import { init, createDailyJobs, processSpecificHour, saveApiLog } from 'logstack';
import dotenv from 'dotenv';
dotenv.config();
class CronLogManager {
constructor() {
this.config = {
dbUri: process.env.DB_URI,
uploadProvider: process.env.UPLOAD_PROVIDER || 'local',
fileFormat: 'json',
// Production-ready configuration
outputDirectory: process.env.OUTPUT_DIR || 'production-logs',
// Environment-specific collections
collections: {
jobsCollectionName: `${process.env.NODE_ENV || 'dev'}_jobs`,
logsCollectionName: `${process.env.NODE_ENV || 'dev'}_logs`,
apiLogsCollectionName: `${process.env.NODE_ENV || 'dev'}_apilogs`
},
// AWS S3 configuration
s3: process.env.UPLOAD_PROVIDER === 's3' ? {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION || 'us-east-1',
bucket: process.env.S3_BUCKET
} : undefined,
logging: {
level: process.env.LOG_LEVEL || 'info',
enableConsole: true,
enableFile: true,
logFilePath: './logs/cron-service.log'
}
};
}
async initialize() {
try {
console.log('๐ Initializing CronLogManager...');
await init(this.config);
console.log('โ
CronLogManager initialized successfully');
// Log configuration summary
console.log('๐ Configuration Summary:');
console.log(` ๐ Output Directory: ${this.config.outputDirectory}`);
console.log(` โ๏ธ Upload Provider: ${this.config.uploadProvider}`);
console.log(` ๐๏ธ Collections: ${Object.values(this.config.collections).join(', ')}`);
return true;
} catch (error) {
console.error('โ Initialization failed:', error);
throw error;
}
}
async createJobsForDateRange(startDate, endDate) {
const jobs = [];
const start = new Date(startDate);
const end = new Date(endDate);
for (let d = start; d <= end; d.setDate(d.getDate() + 1)) {
const dateStr = d.toISOString().split('T')[0];
const job = await createDailyJobs(dateStr, this.config);
jobs.push(job);
console.log(`๐
Created job for ${dateStr} with ${job.hours.length} hours`);
}
return jobs;
}
async processHourRange(date, startHour, endHour) {
const results = [];
for (let hour = startHour; hour <= endHour; hour++) {
try {
console.log(`โก Processing ${date} ${hour}:00-${hour + 1}:00...`);
const result = await processSpecificHour(date, hour, this.config);
results.push({ hour, status: 'success', result });
console.log(`โ
Hour ${hour} processed successfully`);
} catch (error) {
console.error(`โ Hour ${hour} failed:`, error.message);
results.push({ hour, status: 'failed', error: error.message });
}
}
return results;
}
async addApiLog(logData) {
return await saveApiLog(logData, this.config);
}
getConfig() {
return { ...this.config };
}
}
// Usage example
async function main() {
const manager = new CronLogManager();
try {
// Initialize
await manager.initialize();
// Create jobs for the next 7 days
const today = new Date();
const nextWeek = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000);
await manager.createJobsForDateRange(
today.toISOString().split('T')[0],
nextWeek.toISOString().split('T')[0]
);
// Process today's business hours (9 AM to 5 PM)
const todayStr = today.toISOString().split('T')[0];
await manager.processHourRange(todayStr, 9, 17);
console.log('๐ Setup completed successfully!');
} catch (error) {
console.error('โ Setup failed:', error);
process.exit(1);
}
}
// Run if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}
export default CronLogManager;
```
### ๐ 5. Express.js Integration
```javascript
// express-integration.js
const express = require('express');
const { init, createApiLogMiddleware, getApiLogs } = require('logstack');
require('dotenv').config();
const app = express();
app.use(express.json());
async function setupExpressApp() {
// Initialize logstack
const config = {
dbUri: process.env.DB_URI,
uploadProvider: 'local',
outputDirectory: 'api-logs',
collections: {
jobsCollectionName: 'express_jobs',
logsCollectionName: 'express_logs',
apiLogsCollectionName: 'express_apilogs'
}
};
await init(config);
// Add API logging middleware
app.use(createApiLogMiddleware(config));
// Your API routes
app.get('/api/users', (req, res) => {
res.json({
users: [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
]
});
});
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
const newUser = { id: Date.now(), name, email };
res.status(201).json({ user: newUser, message: 'User created successfully' });
});
// API logs endpoint
app.get('/api/logs', async (req, res) => {
try {
const { method, startDate, endDate, limit = 100 } = req.query;
const filters = {};
if (method) filters.method = method;
if (startDate) filters.startDate = new Date(startDate);
if (endDate) filters.endDate = new Date(endDate);
filters.limit = parseInt(limit);
const logs = await getApiLogs(filters, config);
res.json({ logs, count: logs.length });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
service: 'logstack-express'
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`๐ Express server running on port ${PORT}`);
console.log(`๐ API logs automatically captured`);
console.log(`๐ View logs: http://localhost:${PORT}/api/logs`);
});
}
setupExpressApp().catch(console.error);
```
### โ๏ธ 6. AWS S3 Production Setup
```javascript
// aws-production.js
const { init, createDailyJobs, processSpecificHour } = require('logstack');
require('dotenv').config();
class AWSProductionSetup {
constructor() {
this.config = {
dbUri: process.env.DB_URI,
uploadProvider: 's3',
fileFormat: 'json',
// Production AWS configuration
outputDirectory: 'production-api-logs',
collections: {
jobsCollectionName: 'prod_jobs',
logsCollectionName: 'prod_logs',
apiLogsCollectionName: 'prod_apilogs'
},
s3: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION || 'us-east-1',
bucket: process.env.S3_BUCKET
},
retryAttempts: 5,
logging: {
level: 'info',
enableConsole: true,
enableFile: true,
logFilePath: '/var/log/cron-service/production.log'
}
};
}
async validateAWSCredentials() {
console.log('๐ Validating AWS credentials...');
const required = ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'S3_BUCKET'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing AWS environment variables: ${missing.join(', ')}`);
}
console.log('โ
AWS credentials validated');
}
async initialize() {
await this.validateAWSCredentials();
console.log('๐ Initializing AWS Production Setup...');
await init(this.config);
console.log('โ
Production setup initialized');
console.log('๐ Production Configuration:');
console.log(` ๐ชฃ S3 Bucket: ${this.config.s3.bucket}`);
console.log(` ๐ Region: ${this.config.s3.region}`);
console.log(` ๐ Output Directory: ${this.config.outputDirectory}`);
}
async setupDailyProcessing() {
// Setup for the next 30 days
const jobs = [];
const today = new Date();
for (let i = 0; i < 30; i++) {
const date = new Date(today.getTime() + i * 24 * 60 * 60 * 1000);
const dateStr = date.toISOString().split('T')[0];
const job = await createDailyJobs(dateStr, this.config);
jobs.push(job);
if (i % 7 === 0) {
console.log(`๐
Created jobs for week starting ${dateStr}`);
}
}
console.log(`๐ Created ${jobs.length} daily job configurations`);
return jobs;
}
async processBacklog(startDate, endDate) {
console.log(`โฎ๏ธ Processing backlog from ${startDate} to ${endDate}`);
const start = new Date(startDate);
const end = new Date(endDate);
const results = [];
for (let d = start; d <= end; d.setDate(d.getDate() + 1)) {
const dateStr = d.toISOString().split('T')[0];
// Process all 24 hours for each day
for (let hour = 0; hour < 24; hour++) {
try {
await processSpecificHour(dateStr, hour, this.config);
results.push({ date: dateStr, hour, status: 'success' });
} catch (error) {
console.error(`โ Failed ${dateStr} ${hour}:00:`, error.message);
results.push({ date: dateStr, hour, status: 'failed', error: error.message });
}
}
console.log(`โ
Processed all hours for ${dateStr}`);
}
const successful = results.filter(r => r.status === 'success').length;
const failed = results.filter(r => r.status === 'failed').length;
console.log(`๐ Backlog processing complete:`);
console.log(` โ
Successful: ${successful}`);
console.log(` โ Failed: ${failed}`);
console.log(` ๐ Success rate: ${((successful / (successful + failed)) * 100).toFixed(2)}%`);
return results;
}
}
// Production deployment script
async function deployProduction() {
const setup = new AWSProductionSetup();
try {
// Initialize
await setup.initialize();
// Setup daily processing
await setup.setupDailyProcessing();
// Process any backlog (last 7 days)
const today = new Date();
const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
await setup.processBacklog(
weekAgo.toISOString().split('T')[0],
today.toISOString().split('T')[0]
);
console.log('๐ AWS Production deployment completed successfully!');
console.log('๐ Cron jobs will now run automatically every hour');
} catch (error) {
console.error('โ Production deployment failed:', error);
process.exit(1);
}
}
// Run deployment
if (require.main === module) {
deployProduction();
}
module.exports = AWSProductionSetup;
```
### ๐ 7. Performance Testing & Monitoring
```javascript
// performance-test.js
const { init, processSpecificHour, getApiLogs } = require('logstack');
require('dotenv').config();
class PerformanceMonitor {
constructor() {
this.metrics = {
processedRecords: 0,
failedRecords: 0,
totalDuration: 0,
averagePerRecord: 0,
memoryUsage: []
};
}
async testPerformance() {
const config = {
dbUri: process.env.DB_URI,
uploadProvider: 'local',
outputDirectory: 'performance-test',
collections: {
jobsCollectionName: 'perf_jobs',
logsCollectionName: 'perf_logs',
apiLogsCollectionName: 'apilogs' // Use your real data
}
};
await init(config);
console.log('โก Starting performance test...');
const startTime = Date.now();
// Test processing multiple hours in parallel
const today = new Date().toISOString().split('T')[0];
const hours = [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
const promises = hours.map(async (hour) => {
const hourStart = Date.now();
try {
await processSpecificHour(today, hour, config);
const duration = Date.now() - hourStart;
this.metrics.processedRecords++;
console.log(`โ
Hour ${hour}: ${duration}ms`);
return { hour, duration, status: 'success' };
} catch (error) {
this.metrics.failedRecords++;
console.error(`โ Hour ${hour}: ${error.message}`);
return { hour, status: 'failed', error: error.message };
}
});
const results = await Promise.all(promises);
const endTime = Date.now();
this.metrics.totalDuration = endTime - startTime;
this.metrics.averagePerRecord = this.metrics.totalDuration / this.metrics.processedRecords;
console.log('\n๐ Performance Test Results:');
console.log(`โฑ๏ธ Total Duration: ${this.metrics.totalDuration}ms`);
console.log(`โ
Processed Records: ${this.metrics.processedRecords}`);
console.log(`โ Failed Records: ${this.metrics.failedRecords}`);
console.log(`๐ Average per Record: ${this.metrics.averagePerRecord.toFixed(2)}ms`);
console.log(`๐ฏ Success Rate: ${((this.metrics.processedRecords / (this.metrics.processedRecords + this.metrics.failedRecords)) * 100).toFixed(2)}%`);
const memUsage = process.memoryUsage();
console.log(`๐พ Memory Usage: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`);
return results;
}
}
// Run performance test
if (require.main === module) {
const monitor = new PerformanceMonitor();
monitor.testPerformance().catch(console.error);
}
```
### ๐งช 8. Testing Your Implementation
```bash
# Run comprehensive tests
npm run test:final-local # Complete local test
npm run test:final-local:quick # Quick local test
npm run test:final-local:analytics # Analytics only
npm run test:final-local:validate # Validate existing files
# AWS testing
npm run test:aws # Basic AWS test
npm run test:aws-performance # Performance test
npm run test:aws-regions # Multi-region test
# Custom examples
npm run example:custom-collections # Custom collections demo
npm run example:organized-output # Organized directories demo
```
### ๐ 9. Production Deployment Checklist
```bash
# 1. Environment setup
cp .env.example .env
# Edit .env with your credentials
# 2. Database setup
mongosh your-mongodb-uri
# Verify connection and permissions
# 3. AWS setup (if using S3)
aws configure list
aws s3 ls s3://your-bucket-name
# 4. Install and test
npm install
npm run test:final-local
# 5. Deploy to production
node production-setup.js
# 6. Monitor logs
tail -f /var/log/cron-service/production.log
```
### ๐ฏ 10. Real-World Usage Scenarios
**Scenario 1: E-commerce API Logs**
```javascript
const ecommerceConfig = {
dbUri: process.env.DB_URI,
uploadProvider: 's3',
outputDirectory: 'ecommerce-api-logs',
collections: {
jobsCollectionName: 'ecommerce_jobs',
logsCollectionName: 'ecommerce_logs',
apiLogsCollectionName: 'api_requests' // Your existing collection
},
s3: { /* AWS config */ }
};
```
**Scenario 2: Multi-tenant SaaS**
```javascript
const createTenantConfig = (tenantId) => ({
dbUri: process.env.DB_URI,
uploadProvider: 'local',
outputDirectory: `tenant-${tenantId}-logs`,
collections: {
jobsCollectionName: `tenant_${tenantId}_jobs`,
logsCollectionName: `tenant_${tenantId}_logs`,
apiLogsCollectionName: `tenant_${tenantId}_apilogs`
}
});
```
**Scenario 3: Microservices Architecture**
```javascript
const services = ['user-service', 'order-service', 'payment-service'];
services.forEach(async (service) => {
const config = {
dbUri: process.env.DB_URI,
uploadProvider: 's3',
outputDirectory: `${service}-logs`,
collections: {
jobsCollectionName: `${service.replace('-', '_')}_jobs`,
logsCollectionName: `${service.replace('-', '_')}_logs`,
apiLogsCollectionName: `${service.replace('-', '_')}_apilogs`
}
};
await init(config);
});
```
## ๐ฏ API Request Logging
Built-in Express.js middleware for automatic API request logging:
```typescript
import express from "express";
import { createApiLogMiddleware, getApiLogs, init } from "logstack";
const app = express();
// Initialize the service
await init({
dbUri: "mongodb://localhost:27017/cronlog",
uploadProvider: "local",
});
// Add API logging middleware
app.use(createApiLogMiddleware());
// Your API routes
app.get("/api/users", (req, res) => {
res.json({ users: [] });
});
// Query API logs
app.get("/api/logs", async (req, res) => {
const logs = await getApiLogs({
method: "GET",
startDate: new Date("2025-08-25T00:00:00Z"),
endDate: new Date("2025-08-25T23:59:59Z"),
limit: 100,
});
res.json(logs);
});
````
## ๐ Job Management
### Manual Operations
```typescript
import {
createDailyJobs,
runHourlyJob,
getLogs,
getJobStatus,
retryFailedJobs,
} from "logstack";
// Create jobs for specific date
await createDailyJobs("2025-08-25");
// Manually run hourly job
await runHourlyJob(config);
// Get job status
const status = await getJobStatus("2025-08-25", "09-10");
// Get logs
const logs = await getLogs("2025-08-25");
// Retry failed jobs
await retryFailedJobs(config);
```
## ๐งช Testing & Validation
### ๐ Comprehensive Test Results
Our final comprehensive test processed **500 API logs** with perfect results:
```
๐ Final Test Results:
โฑ๏ธ Total Duration: 3.06 seconds
๐ Records Processed: 500
๐ Files Created: 52
๐พ Total Size: 0.55 MB
โก Processing Rate: 163.29 records/second
๐ง Memory Usage: 1025.97 MB
๐ Success Rate: 100.00%
```
### ๐๏ธ Generated File Structure
```
final-test-outputs/
โโโ 2025-08-25/
โ โโโ api-logs-06-00.json (20 records)
โ โโโ api-logs-07-00.json (20 records)
โ โโโ ... (all 24 hours)
โโโ 2025-08-26/
โ โโโ 09-10.json (21 records)
โ โโโ 12-13.json (9 records)
โ โโโ api-logs-{hour}-00.json
โโโ streaming/
โ โโโ 2025-08-25/stream-api-logs-{hour}-00.json
โ โโโ 2025-08-26/stream-api-logs-{hour}-00.json
โโโ analytics/
โโโ final-test-analytics.json
```
### ๐งช Running Tests
```bash
# Complete final test (recommended)
npm run test:final-local
# Quick tests
npm run test:final-local:quick # Faster with fewer records
npm run test:final-local:analytics # Analytics generation only
npm run test:final-local:validate # Validate existing files
# AWS S3 testing
npm run test:aws # Basic AWS functionality
npm run test:aws-performance # High-performance AWS test
npm run test:aws-regions # Multi-region AWS test
# Feature-specific examples
npm run example:custom-collections # Custom collection names
npm run example:organized-output # Organized directory structure
# API logging examples
npm run test:apilogs # API logs processing
npm run inspect:apilogs # Inspect existing API logs
```
### โ
Test Coverage
- **โ
Local File Storage**: 100% success rate with organized structure
- **โ
AWS S3 Integration**: Multi-environment testing with real credentials
- **โ
High-Performance Processing**: 163+ records/second processing rate
- **โ
Memory Efficiency**: Streaming prevents memory overflow
- **โ
Custom Collections**: No database conflicts with custom names
- **โ
Error Handling**: Robust retry mechanisms and error recovery
- **โ
File Validation**: 100% JSON validation success rate
- **โ
Analytics Reporting**: Comprehensive performance metrics
## ๐ Examples & Use Cases
### ๐ Quick Start Examples
```bash
# Basic local setup
npm run example:custom-collections # Custom collection names demo
npm run example:organized-output # Organized directory structure
# API logging examples
npm run test:apilogs # Process API logs from database
npm run inspect:apilogs # Inspect existing API logs data
# Production examples
npm run practical:setup # Production-ready setup
npm run practical:cloud # Cloud storage configuration
npm run practical:inspect # Inspect production data
# Job processing examples
npm run job:create-and-process # Create and process jobs
npm run job:current-hour # Process current hour
npm run job:date-range # Process date range
# Multi-provider examples
npm run example:s3 # AWS S3 example
npm run example:gcs # Google Cloud Storage example
npm run example:azure # Azure Blob Storage example
```
### ๐ก Real-World Implementation Examples
**1. E-commerce Platform:**
```javascript
// E-commerce API logs processing
const ecommerceConfig = {
dbUri: process.env.DB_URI,
uploadProvider: "s3",
outputDirectory: "ecommerce-api-logs",
collections: {
jobsCollectionName: "ecommerce_jobs",
logsCollectionName: "ecommerce_logs",
apiLogsCollectionName: "api_requests",
},
s3: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: "us-east-1",
bucket: "ecommerce-logs-bucket",
},
};
```
**2. Multi-tenant SaaS:**
```javascript
// Separate logs per tenant
const createTenantConfig = (tenantId) => ({
dbUri: process.env.DB_URI,
uploadProvider: "local",
outputDirectory: `tenant-${tenantId}-logs`,
collections: {
jobsCollectionName: `tenant_${tenantId}_jobs`,
logsCollectionName: `tenant_${tenantId}_logs`,
apiLogsCollectionName: `tenant_${tenantId}_apilogs`,
},
});
```
**3. Microservices Architecture:**
```javascript
// Separate configs per service
const services = ["user-service", "order-service", "payment-service"];
services.forEach(async (service) => {
const config = {
outputDirectory: `${service}-logs`,
collections: {
jobsCollectionName: `${service.replace("-", "_")}_jobs`,
logsCollectionName: `${service.replace("-", "_")}_logs`,
apiLogsCollectionName: `${service.replace("-", "_")}_apilogs`,
},
};
await init(config);
});
```
## ๐๏ธ Project Structure
```
logstack/
โโโ src/
โ โโโ main.ts # Main initialization
โ โโโ jobs.ts # Job management logic
โ โโโ logs.ts # Log querying
โ โโโ apiLogs.ts # API logging functionality
โโโ lib/
โ โโโ db.ts # Database connection
โ โโโ cron.ts # Cron job setup
โ โโโ fileProcessor.ts # File processing logic
โ โโโ fileWriters.ts # File format writers
โ โโโ uploadProviders.ts # Cloud storage providers
โ โโโ validation.ts # Configuration validation
โ โโโ logger.ts # Winston logging setup
โ โโโ userDataProvider.ts # Custom data provider
โโโ models/
โ โโโ job.ts # Job schema
โ โโโ log.ts # Log schema
โ โโโ apiLog.ts # API log schema
โโโ types/
โ โโโ config.d.ts # TypeScript definitions
โโโ examples/
โ โโโ basic.ts # Basic usage
โ โโโ advanced.ts # Advanced configuration
โ โโโ multiProvider.ts # Multi-cloud examples
โ โโโ apiLogs.ts # API logging examples
โโโ test/
โโโ jobs.test.ts # Job tests
โโโ comprehensive.test.ts # Full test suite
```
## ๐ง Custom Data Provider
Override the default data provider to use your own data source:
```typescript
// lib/userDataProvider.ts
export async function getDataForHour(
date: string,
hourRange: string
): Promise<any> {
// Your custom data fetching logic
const logs = await YourDatabase.find({
timestamp: {
$gte: new Date(`${date}T${hourRange.split("-")[0]}:00:00Z`),
$lt: new Date(`${date}T${hourRange.split("-")[1]}:00:00Z`),
},
});
return logs;
}
```
## ๏ฟฝ Production Deployment
### ๐ Pre-deployment Checklist
```bash
# 1. Environment Configuration
cp .env.example .env
# Configure: DB_URI, AWS credentials, etc.
# 2. Test Local Setup
npm run test:final-local
# Verify: 100% success rate, file generation working
# 3. Test Cloud Storage (if using)
npm run test:aws
# Verify: S3 uploads working, credentials valid
# 4. Validate Database Connection
npm run inspect:apilogs
# Verify: Can access your API logs collection
# 5. Performance Testing
npm run test:final-local:quick
# Verify: Processing speed meets requirements
```
### ๐ Production Performance Metrics
Based on comprehensive testing with **real API logs data**:
| Metric | Result | Status |
| ---------------------- | ---------------------- | ------------ |
| **Processing Rate** | 163+ records/sec | โ
Excellent |
| **Memory Usage** | ~1GB for 500 records | โ
Efficient |
| **File Generation** | 52 files in 3.06 sec | โ
Fast |
| **Success Rate** | 100% | โ
Perfect |
| **Storage Efficiency** | 0.55MB for 500 records | โ
Optimized |
### ๏ฟฝ๐ Cron Schedule & Automation
The package automatically sets up these production cron jobs:
```javascript
// Automatic cron jobs (no manual setup required)
{
dailyCron: '0 0 * * *', // Create daily jobs at midnight
hourlyCron: '0 * * * *', // Process each hour
retryCron: '*/30 * * * *' // Retry failed jobs every 30 min
}
```
**What happens automatically:**
1. **Midnight**: Creates 24 hourly job slots for the new day
2. **Every Hour**: Processes the current hour's API logs
3. **Every 30 Minutes**: Retries any failed processing jobs
4. **Continuous**: Monitors and logs all operations
### ๐ Monitoring & Analytics
**Real-time Monitoring:**
```bash
# View live logs
tail -f logs/cron-service.log
# Check analytics
npm run test:final-local:analytics
# Validate generated files
npm run test:final-local:validate
```
**Analytics Include:**
- Processing performance metrics
- Success/failure rates
- Memory usage patterns
- File size and count statistics
- Method and status code distributions
## ๐๏ธ Project Structure
```
your-project/
โโโ node_modules/
โ โโโ logstack/
โโโ final-test-outputs/ # Generated files (organized)
โ โโโ 2025-08-25/
โ โ โโโ api-logs-09-00.json # Hour 9-10 API logs
โ โ โโโ api-logs-10-00.json # Hour 10-11 API logs
โ โ โโโ 09-10.json # Job-generated files
โ โโโ streaming/ # Streaming processor output
โ โโโ analytics/ # Performance reports
โโโ logs/ # Service logs
โ โโโ cron-service.log
โโโ .env # Environment configuration
โโโ package.json
โโโ your-app.js # Your implementation
```
## ๐ฏ Best Practices
### ๐๏ธ Database Organization
```javascript
// โ
Good: Environment-specific collections
const prodConfig = {
collections: {
jobsCollectionName: "prod_jobs",
logsCollectionName: "prod_logs",
apiLogsCollectionName: "prod_apilogs",
},
};
const devConfig = {
collections: {
jobsCollectionName: "dev_jobs",
logsCollectionName: "dev_logs",
apiLogsCollectionName: "dev_apilogs",
},
};
// โ Avoid: Using default collection names in production
const badConfig = {
// Will conflict with other instances
// collections: undefined // Uses defaults: 'jobs', 'logs', 'apilogs'
};
```
### ๐ File Organization
```javascript
// โ
Good: Organized directory structure
const organizedConfig = {
outputDirectory: "production-api-logs", // Clean separation
uploadProvider: "s3",
s3: { bucket: "company-api-logs-prod" },
};
// โ Avoid: Files in project root
const messyConfig = {
// outputDirectory: undefined, // Files in project root
uploadProvider: "local",
};
```
### โก Performance Optimization
```javascript
// โ
Good: Batch processing for large datasets
const performantConfig = {
retryAttempts: 5, // Handle transient failures
fileFormat: "json", // Most efficient for APIs
logging: { level: "info" }, // Reduce log noise
};
// Configure batch size for your data volume
const batchSize = process.env.NODE_ENV === "production" ? 1000 : 100;
```
## ๐ง Configuration Best Practices
### ๐ Environment-Specific Configs
```javascript
// config/production.js
module.exports = {
dbUri: process.env.PROD_DB_URI,
uploadProvider: "s3",
outputDirectory: "production-api-logs",
collections: {
jobsCollectionName: "prod_jobs",
logsCollectionName: "prod_logs",
apiLogsCollectionName: "prod_apilogs",
},
s3: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION,
bucket: process.env.PROD_S3_BUCKET,
},
retryAttempts: 5,
logging: { level: "info", enableFile: true },
};
// config/development.js
module.exports = {
dbUri: process.env.DEV_DB_URI,
uploadProvider: "local",
outputDirectory: "dev-api-logs",
collections: {
jobsCollectionName: "dev_jobs",
logsCollectionName: "dev_logs",
apiLogsCollectionName: "dev_apilogs",
},
retryAttempts: 3,
logging: { level: "debug", enableConsole: true },
};
```
## ๐ Troubleshooting
### Common Issues
1. **MongoDB Connection**: Ensure MongoDB is running and the connection string is correct
2. **Cloud Storage Permissions**: Verify credentials have proper read/write permissions
3. **File Path Issues**: Check that the application has write permissions for local storage
4. **Timezone Issues**: Set the correct timezone in configuration
### Debug Logging
Enable debug logging for detailed information:
```typescript
await init({
// ... other config
logging: {
level: "debug",
enableConsole: true,
enableFile: true,
logFilePath: "./debug.log",
},
});
```
## ๐ License
MIT License - see LICENSE file for details
## ๐ค Contributing
1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Submit a pull request
## ๏ฟฝ Complete Documentation
### ๐ Getting Started
- **[Quick Start Guide](./examples/quickStart.ts)** - Copy-paste examples for immediate use
- **[Implementation Checklist](./IMPLEMENTATION_CHECKLIST.md)** - Step-by-step setup guide
- **[Complete Step-by-Step Guide](./COMPLETE_STEP_BY_STEP_GUIDE.md)** - Comprehensive usage documentation
### ๐ฏ Key Features
- **[Custom Collection Names](./CUSTOM_COLLECTIONS.md)** - Avoid database conflicts
- **[Organized Output Directory](./OUTPUT_DIRECTORY.md)** - Clean project structure
- **[Implementation Complete](./IMPLEMENTATION_COMPLETE.md)** - Features overview
### ๐งช Testing & Examples
- **[Testing Guide](./TESTING_GUIDE.md)** - How to test your setup
- **[API Logs Testing](./APILOGS_TESTING_GUIDE.md)** - API logging validation
- **[Examples Folder](./examples/)** - Working code samples
### ๐ Reference
- **[Configuration Options](./FLEXIBLE_API_LOGS.md)** - All available settings
- **[Usage Guide](./COMPLETE_USAGE_GUIDE.md)** - Detailed API reference
## ๐ฏ Quick Implementation
**Choose your setup:**
1. **Basic Setup** (Recommended for beginners):
```typescript
const config = {
dbUri: "mongodb://localhost:27017/myapp",
uploadProvider: "local",
outputDirectory: "api-logs",
collections: {
jobsCollectionName: "myapp_jobs",
logsCollectionName: "myapp_logs",
},
};
```
2. **Production Setup**:
```typescript
const config = {
dbUri: process.env.DB_URI,
uploadProvider: "s3",
outputDirectory: "production-logs",
collections: {
jobsCollectionName: "prod_jobs",
logsCollectionName: "prod_logs",
},
s3: {
/* S3 credentials */
},
};
```
3. **Multi-Service Setup**:
```typescript
const createConfig = (serviceName) => ({
dbUri: process.env.DB_URI,
uploadProvider: "local",
outputDirectory: `${serviceName}-logs`,
collections: {
jobsCollectionName: `${serviceName}_jobs`,
logsCollectionName: `${serviceName}_logs`,
},
});
```
**Start here:** [Implementation Checklist](./IMPLEMENTATION_CHECKLIST.md) โ
## ๐ Support
- **๐ Documentation**: Check the comprehensive guides above
- **๐ Issues**: Create an issue on GitHub for bugs or feature requests
- **๐ก Examples**: Review the examples folder for usage patterns
- **๐งช Testing**: Use the testing guides to validate your setup
````
#### Local Storage
```typescript
{
uploadProvider: "local" // Files saved to local filesystem
}
````
### Complete Configuration Interface
```typescript
interface Config {
dbUri: string;
uploadProvider: "local" | "s3" | "gcs" | "azure";
fileFormat?: "json" | "csv" | "txt";
retryAttempts?: number;
dailyCron?: string; // Default: '0 0 * * *' (midnight)
hourlyCron?: string; // Default: '0 * * * *' (every hour)
timezone?: string; // Default: 'UTC'
logging?: {
level: "debug" | "info" | "warn" | "error";
enableConsole?: boolean;
enableFile?: boolean;
logFilePath?: string;
};
// ... provider-specific configs
}
```
// Manually trigger daily job creation
await createDailyJobs();
// Manually trigger hourly job
await runHourlyJob();
// Fetch logs
const logs = await getLogs("2025-08-25", "09-10");
// Fetch job status
const status = await getJobStatus("2025-08-25", "09-10");
```
## Custom Data Provider
Override `lib/userDataProvider.ts` to provide your own data for file generation.
## Running Tests
This package uses Jest for testing. To run tests:
```
npm run build
npx jest
```
## Examples
See the `examples/` folder for usage samples.
To run the basic example:
```
npm run build
node examples/basic.js
```
Or use ts-node for TypeScript:
```
npx ts-node examples/basic.ts
```
## License
MIT
```