Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
e133da8076 | |||
d502ab8cc9 | |||
d1c05fb9ae | |||
f81971d148 | |||
aa6a27970a | |||
b31d9f0c36 | |||
e6cef68a26 | |||
aa327efeac |
26
changelog.md
26
changelog.md
@@ -1,5 +1,31 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-09-01 - 3.1.9 - fix(docs)
|
||||||
|
Update README: expand documentation, examples and usage guides
|
||||||
|
|
||||||
|
- Fully rewrote README to a comprehensive documentation page with badges, motivation and feature overview.
|
||||||
|
- Added Quick Start, detailed usage examples and code snippets for Smartlog, destinations, and custom destinations.
|
||||||
|
- Documented interactive console features (spinners, progress bars) including non-interactive fallbacks and configuration options.
|
||||||
|
- Expanded sections on built-in destinations (console, file, devtools, ClickHouse, receiver) with practical examples and env-driven configuration.
|
||||||
|
- Added integration examples (PM2, Docker), CLI usage, advanced features (context management, scoped logging, minimum log levels) and best practices.
|
||||||
|
- Included API reference pointers and contributing / license information.
|
||||||
|
|
||||||
|
## 2025-05-20 - 3.1.8 - fix(devDependencies)
|
||||||
|
Update devDependencies for tstest and Node types
|
||||||
|
|
||||||
|
- Bump @git.zone/tstest from ^1.7.0 to ^1.9.0
|
||||||
|
- Bump @types/node from ^22.15.18 to ^22.15.20
|
||||||
|
|
||||||
|
## 2025-05-20 - 3.1.7 - fix(ts_destination_local)
|
||||||
|
Update debug log color: set textColor to 'pink' in DestinationLocal.
|
||||||
|
|
||||||
|
- Changed debug log text color from 'gray' to 'pink' for improved consistency in log output
|
||||||
|
|
||||||
|
## 2025-05-20 - 3.1.6 - fix(ts_destination_local)
|
||||||
|
Update debug prefix color in DestinationLocal: change from gray to pink for improved visibility.
|
||||||
|
|
||||||
|
- Adjusted the 'debug' log prefix color in classes.destinationlocal.ts to use 'pink' instead of 'gray'.
|
||||||
|
|
||||||
## 2025-05-20 - 3.1.5 - fix(core)
|
## 2025-05-20 - 3.1.5 - fix(core)
|
||||||
Maintain and verify project metadata and commit info consistency
|
Maintain and verify project metadata and commit info consistency
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartlog",
|
"name": "@push.rocks/smartlog",
|
||||||
"version": "3.1.5",
|
"version": "3.1.9",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A minimalistic, distributed, and extensible logging tool supporting centralized log management.",
|
"description": "A minimalistic, distributed, and extensible logging tool supporting centralized log management.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -45,8 +45,8 @@
|
|||||||
"@git.zone/tsbuild": "^2.5.1",
|
"@git.zone/tsbuild": "^2.5.1",
|
||||||
"@git.zone/tsbundle": "^2.2.5",
|
"@git.zone/tsbundle": "^2.2.5",
|
||||||
"@git.zone/tsrun": "^1.3.3",
|
"@git.zone/tsrun": "^1.3.3",
|
||||||
"@git.zone/tstest": "^1.7.0",
|
"@git.zone/tstest": "^1.9.0",
|
||||||
"@types/node": "^22.15.18"
|
"@types/node": "^22.15.20"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||||
|
964
pnpm-lock.yaml
generated
964
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
814
readme.md
814
readme.md
@@ -1,286 +1,734 @@
|
|||||||
# @push.rocks/smartlog
|
# @push.rocks/smartlog 🚀
|
||||||
|
*The ultimate TypeScript logging solution for modern applications*
|
||||||
|
|
||||||
Minimalistic distributed and extensible logging tool for TypeScript and JavaScript applications.
|
[](https://www.npmjs.com/package/@push.rocks/smartlog)
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
## Install
|
> **smartlog** is a powerful, distributed, and extensible logging system designed for the cloud-native era. Whether you're debugging locally, monitoring production systems, or building complex microservices, smartlog adapts to your needs with style. 🎯
|
||||||
|
|
||||||
Install `@push.rocks/smartlog` using pnpm (recommended), npm, or yarn:
|
## 🌟 Why smartlog?
|
||||||
|
|
||||||
```sh
|
- **🎨 Beautiful Console Output**: Color-coded, formatted logs that are actually readable
|
||||||
|
- **🔌 Extensible Architecture**: Plug in any destination - databases, files, remote servers
|
||||||
|
- **🌍 Distributed by Design**: Built for microservices with correlation and context tracking
|
||||||
|
- **⚡ Zero-Config Start**: Works out of the box, scales when you need it
|
||||||
|
- **🎭 Interactive CLI Tools**: Spinners and progress bars that handle non-TTY environments gracefully
|
||||||
|
- **📊 Structured Logging**: JSON-based for easy parsing and analysis
|
||||||
|
- **🔍 Smart Filtering**: Log levels and context-based filtering
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
# Using pnpm (recommended)
|
# Using pnpm (recommended)
|
||||||
pnpm add @push.rocks/smartlog
|
pnpm add @push.rocks/smartlog
|
||||||
|
|
||||||
# Using npm
|
# Using npm
|
||||||
npm install @push.rocks/smartlog --save
|
npm install @push.rocks/smartlog
|
||||||
|
|
||||||
# Using yarn
|
# Using yarn
|
||||||
yarn add @push.rocks/smartlog
|
yarn add @push.rocks/smartlog
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensure you have TypeScript and Node.js installed for TypeScript projects.
|
## 🚀 Quick Start
|
||||||
|
|
||||||
## Package Exports
|
### Your First Logger
|
||||||
|
|
||||||
The package provides the following exports:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Main module
|
|
||||||
import { Smartlog, LogGroup, ConsoleLog } from '@push.rocks/smartlog';
|
|
||||||
|
|
||||||
// Type definitions and interfaces
|
|
||||||
import { ILogPackage, ILogDestination, TLogLevel } from '@push.rocks/smartlog/interfaces';
|
|
||||||
|
|
||||||
// Interactive console features (spinners, progress bars)
|
|
||||||
import { SmartlogSourceInteractive, SmartlogProgressBar } from '@push.rocks/smartlog/source-interactive';
|
|
||||||
|
|
||||||
// Context management
|
|
||||||
import { ... } from '@push.rocks/smartlog/context';
|
|
||||||
|
|
||||||
// Log destinations
|
|
||||||
import { SmartlogDestinationClickhouse } from '@push.rocks/smartlog/destination-clickhouse';
|
|
||||||
import { SmartlogDestinationDevtools } from '@push.rocks/smartlog/destination-devtools';
|
|
||||||
import { SmartlogDestinationFile } from '@push.rocks/smartlog/destination-file';
|
|
||||||
import { DestinationLocal } from '@push.rocks/smartlog/destination-local';
|
|
||||||
import { SmartlogDestinationReceiver } from '@push.rocks/smartlog/destination-receiver';
|
|
||||||
|
|
||||||
// Receiver functionality
|
|
||||||
import { SmartlogReceiver } from '@push.rocks/smartlog/receiver';
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
`@push.rocks/smartlog` is a flexible, extensible logging tool designed for distributed systems. It provides a consistent logging interface across different environments while being lightweight and customizable.
|
|
||||||
|
|
||||||
### Creating a Logger Instance
|
|
||||||
|
|
||||||
Start by importing `Smartlog` and create a logger instance:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Smartlog } from '@push.rocks/smartlog';
|
import { Smartlog } from '@push.rocks/smartlog';
|
||||||
|
|
||||||
|
// Create a logger with context
|
||||||
const logger = new Smartlog({
|
const logger = new Smartlog({
|
||||||
logContext: {
|
logContext: {
|
||||||
company: 'My Company',
|
company: 'MyStartup',
|
||||||
companyunit: 'Cloud Team',
|
companyunit: 'Backend Team',
|
||||||
containerName: 'api-service',
|
containerName: 'api-gateway',
|
||||||
environment: 'production', // 'local', 'test', 'staging', 'production'
|
environment: 'production',
|
||||||
runtime: 'node', // 'node', 'chrome', 'rust', 'deno', 'cloudflare_workers'
|
runtime: 'node',
|
||||||
zone: 'us-west',
|
zone: 'eu-central'
|
||||||
},
|
}
|
||||||
minimumLogLevel: 'info', // Optional, defaults to 'silly'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable console output
|
// Enable beautiful console output
|
||||||
logger.enableConsole();
|
logger.enableConsole();
|
||||||
|
|
||||||
|
// Start logging!
|
||||||
|
logger.log('info', '🎉 Application started successfully');
|
||||||
|
logger.log('error', '💥 Database connection failed', {
|
||||||
|
errorCode: 'DB_TIMEOUT',
|
||||||
|
attemptCount: 3
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
The context enriches logs with valuable information for filtering and analysis across distributed systems.
|
### Using the Default Logger
|
||||||
|
|
||||||
### Logging Messages
|
For quick prototyping and simple applications:
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Basic logging
|
|
||||||
logger.log('info', 'User authenticated successfully');
|
|
||||||
logger.log('error', 'Database connection failed', { errorCode: 'DB_CONN_ERR', retryCount: 3 });
|
|
||||||
logger.log('warn', 'Rate limit approaching', { currentRate: 95, limit: 100 });
|
|
||||||
|
|
||||||
// Log levels: 'silly', 'info', 'debug', 'note', 'ok', 'success', 'warn', 'error', 'lifecycle'
|
|
||||||
```
|
|
||||||
|
|
||||||
The third parameter accepts any additional data to attach to the log entry.
|
|
||||||
|
|
||||||
### Default Logger
|
|
||||||
|
|
||||||
For simple cases, use the built-in default logger:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { defaultLogger } from '@push.rocks/smartlog';
|
import { defaultLogger } from '@push.rocks/smartlog';
|
||||||
|
|
||||||
defaultLogger.log('info', 'Application started');
|
defaultLogger.log('info', 'This is so easy!');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Log Groups
|
## 📚 Core Concepts
|
||||||
|
|
||||||
Group related logs for better traceability:
|
### Log Levels
|
||||||
|
|
||||||
|
smartlog supports semantic log levels for different scenarios:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Create a log group with optional transaction ID
|
// Lifecycle events
|
||||||
const requestGroup = logger.createLogGroup('tx-123456');
|
logger.log('lifecycle', '🔄 Container starting up...');
|
||||||
|
|
||||||
// Logs within this group will be correlated
|
// Success states
|
||||||
requestGroup.log('info', 'Processing payment request');
|
logger.log('success', '✅ Payment processed');
|
||||||
requestGroup.log('debug', 'Validating payment details');
|
logger.log('ok', '👍 Health check passed');
|
||||||
requestGroup.log('success', 'Payment processed successfully');
|
|
||||||
|
// Information and debugging
|
||||||
|
logger.log('info', '📋 User profile updated');
|
||||||
|
logger.log('note', '📌 Cache invalidated');
|
||||||
|
logger.log('debug', '🔍 Query execution plan', { sql: 'SELECT * FROM users' });
|
||||||
|
|
||||||
|
// Warnings and errors
|
||||||
|
logger.log('warn', '⚠️ Memory usage above 80%');
|
||||||
|
logger.log('error', '❌ Failed to send email');
|
||||||
|
|
||||||
|
// Verbose output
|
||||||
|
logger.log('silly', '🔬 Entering function processPayment()');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom Log Destinations
|
### Log Groups for Correlation
|
||||||
|
|
||||||
Extend logging capabilities by adding custom destinations:
|
Perfect for tracking request flows through your system:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Smartlog, ILogDestination } from '@push.rocks/smartlog';
|
// Track a user request through multiple operations
|
||||||
|
const requestGroup = logger.createLogGroup('req-7f3a2b');
|
||||||
|
|
||||||
class DatabaseLogDestination implements ILogDestination {
|
requestGroup.log('info', 'Received POST /api/users');
|
||||||
async handleLog(logPackage) {
|
requestGroup.log('debug', 'Validating request body');
|
||||||
// Store log in database
|
requestGroup.log('info', 'Creating user in database');
|
||||||
await db.logs.insert({
|
requestGroup.log('success', 'User created successfully', { userId: 'usr_123' });
|
||||||
timestamp: new Date(logPackage.timestamp),
|
|
||||||
|
// All logs in the group share the same correlation ID
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Log Destinations
|
||||||
|
|
||||||
|
### Built-in Destinations
|
||||||
|
|
||||||
|
#### 🖥️ Local Console (Enhanced)
|
||||||
|
|
||||||
|
Beautiful, colored output for local development:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { DestinationLocal } from '@push.rocks/smartlog/destination-local';
|
||||||
|
|
||||||
|
const localDestination = new DestinationLocal({
|
||||||
|
logLevel: 'debug' // Optional: filter by minimum log level
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.addLogDestination(localDestination);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 📁 File Logging
|
||||||
|
|
||||||
|
Persist logs to files with automatic rotation support:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartlogDestinationFile } from '@push.rocks/smartlog/destination-file';
|
||||||
|
|
||||||
|
const fileDestination = new SmartlogDestinationFile('./logs/app.log');
|
||||||
|
logger.addLogDestination(fileDestination);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 🌐 Browser DevTools
|
||||||
|
|
||||||
|
Optimized for browser environments with styled console output:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartlogDestinationDevtools } from '@push.rocks/smartlog/destination-devtools';
|
||||||
|
|
||||||
|
const devtools = new SmartlogDestinationDevtools();
|
||||||
|
logger.addLogDestination(devtools);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 📊 ClickHouse Analytics
|
||||||
|
|
||||||
|
Store logs in ClickHouse for powerful analytics:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartlogDestinationClickhouse } from '@push.rocks/smartlog/destination-clickhouse';
|
||||||
|
|
||||||
|
const clickhouse = await SmartlogDestinationClickhouse.createAndStart({
|
||||||
|
host: 'analytics.example.com',
|
||||||
|
port: 8123,
|
||||||
|
database: 'logs',
|
||||||
|
user: 'logger',
|
||||||
|
password: process.env.CLICKHOUSE_PASSWORD
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.addLogDestination(clickhouse);
|
||||||
|
|
||||||
|
// Query your logs with SQL!
|
||||||
|
// SELECT * FROM logs WHERE level = 'error' AND timestamp > now() - INTERVAL 1 HOUR
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 🔗 Remote Receiver
|
||||||
|
|
||||||
|
Send logs to a centralized logging service:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartlogDestinationReceiver } from '@push.rocks/smartlog/destination-receiver';
|
||||||
|
|
||||||
|
const receiver = new SmartlogDestinationReceiver({
|
||||||
|
endpoint: 'https://logs.mycompany.com/ingest',
|
||||||
|
apiKey: process.env.LOG_API_KEY,
|
||||||
|
batchSize: 100, // Send logs in batches
|
||||||
|
flushInterval: 5000 // Flush every 5 seconds
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.addLogDestination(receiver);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🛠️ Custom Destinations
|
||||||
|
|
||||||
|
Build your own destination for any logging backend:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ILogDestination, ILogPackage } from '@push.rocks/smartlog/interfaces';
|
||||||
|
|
||||||
|
class ElasticsearchDestination implements ILogDestination {
|
||||||
|
private client: ElasticsearchClient;
|
||||||
|
|
||||||
|
constructor(config: ElasticsearchConfig) {
|
||||||
|
this.client = new ElasticsearchClient(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleLog(logPackage: ILogPackage): Promise<void> {
|
||||||
|
await this.client.index({
|
||||||
|
index: `logs-${new Date().toISOString().split('T')[0]}`,
|
||||||
|
body: {
|
||||||
|
'@timestamp': logPackage.timestamp,
|
||||||
level: logPackage.level,
|
level: logPackage.level,
|
||||||
message: logPackage.message,
|
message: logPackage.message,
|
||||||
|
context: logPackage.context,
|
||||||
data: logPackage.data,
|
data: logPackage.data,
|
||||||
context: logPackage.context
|
correlation: logPackage.correlation
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the custom destination to your logger
|
// Use your custom destination
|
||||||
logger.addLogDestination(new DatabaseLogDestination());
|
logger.addLogDestination(new ElasticsearchDestination({
|
||||||
```
|
node: 'https://elasticsearch.example.com'
|
||||||
|
|
||||||
### Built-in Destinations
|
|
||||||
|
|
||||||
SmartLog comes with several built-in destinations for various logging needs:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Log to a file
|
|
||||||
import { SmartlogDestinationFile } from '@push.rocks/smartlog/destination-file';
|
|
||||||
logger.addLogDestination(new SmartlogDestinationFile('/path/to/logfile.log'));
|
|
||||||
|
|
||||||
// Colorful local console logging
|
|
||||||
import { DestinationLocal } from '@push.rocks/smartlog/destination-local';
|
|
||||||
logger.addLogDestination(new DestinationLocal());
|
|
||||||
|
|
||||||
// Browser DevTools with colored formatting
|
|
||||||
import { SmartlogDestinationDevtools } from '@push.rocks/smartlog/destination-devtools';
|
|
||||||
logger.addLogDestination(new SmartlogDestinationDevtools());
|
|
||||||
|
|
||||||
// ClickHouse database logging
|
|
||||||
import { SmartlogDestinationClickhouse } from '@push.rocks/smartlog/destination-clickhouse';
|
|
||||||
const clickhouse = await SmartlogDestinationClickhouse.createAndStart({
|
|
||||||
host: 'clickhouse.example.com',
|
|
||||||
port: 8123,
|
|
||||||
user: 'username',
|
|
||||||
password: 'password',
|
|
||||||
database: 'logs_db'
|
|
||||||
});
|
|
||||||
logger.addLogDestination(clickhouse);
|
|
||||||
|
|
||||||
// Remote receiver logging
|
|
||||||
import { SmartlogDestinationReceiver } from '@push.rocks/smartlog/destination-receiver';
|
|
||||||
logger.addLogDestination(new SmartlogDestinationReceiver({
|
|
||||||
endpoint: 'https://logs.example.com/api/logs'
|
|
||||||
}));
|
}));
|
||||||
```
|
```
|
||||||
|
|
||||||
### Interactive Console Features
|
## 🎨 Interactive Console Features
|
||||||
|
|
||||||
For CLI applications, use the interactive console features:
|
### Spinners
|
||||||
|
|
||||||
|
Create beautiful loading animations that degrade gracefully in CI/CD:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { SmartlogSourceInteractive, SmartlogProgressBar } from '@push.rocks/smartlog/source-interactive';
|
import { SmartlogSourceInteractive } from '@push.rocks/smartlog/source-interactive';
|
||||||
```
|
|
||||||
|
|
||||||
#### Spinners
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const spinner = new SmartlogSourceInteractive();
|
const spinner = new SmartlogSourceInteractive();
|
||||||
|
|
||||||
// Start a spinner with text
|
// Basic usage
|
||||||
spinner.text('Loading data...');
|
spinner.text('🔄 Fetching data from API...');
|
||||||
|
// ... perform async operation
|
||||||
|
spinner.finishSuccess('✅ Data fetched successfully!');
|
||||||
|
|
||||||
|
// Chained operations
|
||||||
|
spinner
|
||||||
|
.text('📡 Connecting to database')
|
||||||
|
.successAndNext('🔍 Running migrations')
|
||||||
|
.successAndNext('🌱 Seeding data')
|
||||||
|
.finishSuccess('🎉 Database ready!');
|
||||||
|
|
||||||
// Customize appearance
|
// Customize appearance
|
||||||
spinner.setSpinnerStyle('dots'); // 'dots', 'line', 'star', 'simple'
|
spinner
|
||||||
spinner.setColor('blue'); // 'red', 'green', 'yellow', 'blue', etc.
|
.setSpinnerStyle('dots') // dots, line, star, simple
|
||||||
spinner.setSpeed(80); // Animation speed in milliseconds
|
.setColor('cyan') // any terminal color
|
||||||
|
.setSpeed(80) // animation speed in ms
|
||||||
|
.text('🚀 Deploying application...');
|
||||||
|
|
||||||
// Update spinner status
|
// Handle failures
|
||||||
spinner.text('Processing records...');
|
try {
|
||||||
|
await deployApp();
|
||||||
// Complete with success or failure
|
spinner.finishSuccess('✅ Deployed!');
|
||||||
spinner.finishSuccess('Data loaded successfully!');
|
} catch (error) {
|
||||||
spinner.finishFail('Failed to load data!');
|
spinner.finishFail('❌ Deployment failed');
|
||||||
|
}
|
||||||
// Chain operations
|
|
||||||
spinner.text('Connecting to server')
|
|
||||||
.successAndNext('Fetching records')
|
|
||||||
.successAndNext('Processing data')
|
|
||||||
.finishSuccess('All done!');
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Progress Bars
|
### Progress Bars
|
||||||
|
|
||||||
|
Track long-running operations with style:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const progressBar = new SmartlogProgressBar({
|
import { SmartlogProgressBar } from '@push.rocks/smartlog/source-interactive';
|
||||||
total: 100, // Total number of items
|
|
||||||
width: 40, // Width of the progress bar
|
// Create a progress bar
|
||||||
complete: '█', // Character for completed section
|
const progress = new SmartlogProgressBar({
|
||||||
incomplete: '░', // Character for incomplete section
|
total: 100,
|
||||||
showEta: true, // Show estimated time remaining
|
width: 40,
|
||||||
showPercent: true, // Show percentage
|
complete: '█',
|
||||||
showCount: true // Show count (e.g., "50/100")
|
incomplete: '░',
|
||||||
|
showEta: true,
|
||||||
|
showPercent: true,
|
||||||
|
showCount: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update progress
|
// Update progress
|
||||||
progressBar.update(25); // Set to 25% progress
|
for (let i = 0; i <= 100; i++) {
|
||||||
|
progress.update(i);
|
||||||
|
await someAsyncWork();
|
||||||
|
}
|
||||||
|
|
||||||
// Increment progress
|
progress.complete();
|
||||||
progressBar.increment(5); // Increase by 5 units
|
|
||||||
|
|
||||||
// Change color
|
// Real-world example: Processing files
|
||||||
progressBar.setColor('blue');
|
const files = await getFiles();
|
||||||
|
const progress = new SmartlogProgressBar({
|
||||||
|
total: files.length,
|
||||||
|
width: 50
|
||||||
|
});
|
||||||
|
|
||||||
// Complete the progress bar
|
for (const [index, file] of files.entries()) {
|
||||||
progressBar.complete();
|
await processFile(file);
|
||||||
|
progress.increment(); // or progress.update(index + 1)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Non-Interactive Environments
|
### Non-Interactive Fallback
|
||||||
|
|
||||||
Both spinners and progress bars automatically detect non-interactive environments (CI/CD, piped output) and fallback to plain text logging:
|
Both spinners and progress bars automatically detect non-interactive environments (CI/CD, Docker logs, piped output) and fallback to simple text output:
|
||||||
|
|
||||||
```
|
```
|
||||||
[Loading] Connecting to server
|
[Loading] Connecting to database
|
||||||
[Success] Connected to server
|
[Success] Connected to database
|
||||||
[Loading] Fetching records
|
[Loading] Running migrations
|
||||||
|
Progress: 25% (25/100)
|
||||||
Progress: 50% (50/100)
|
Progress: 50% (50/100)
|
||||||
Progress: 100% (100/100)
|
Progress: 100% (100/100)
|
||||||
[Success] Fetching complete
|
[Success] Migrations complete
|
||||||
```
|
```
|
||||||
|
|
||||||
## Advanced Usage
|
## 🔧 Advanced Features
|
||||||
|
|
||||||
### Capturing All Console Output
|
### Context Management
|
||||||
|
|
||||||
Capture all `console.log` and `console.error` output through Smartlog:
|
Add context that flows through your entire application:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
logger.enableConsole({ captureAll: true });
|
// Set global context
|
||||||
|
logger.addLogContext({
|
||||||
|
requestId: 'req-123',
|
||||||
|
userId: 'user-456',
|
||||||
|
feature: 'payment-processing'
|
||||||
|
});
|
||||||
|
|
||||||
|
// All subsequent logs include this context
|
||||||
|
logger.log('info', 'Processing payment');
|
||||||
|
// Output includes: { ...context, message: 'Processing payment' }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scoped Logging
|
||||||
|
|
||||||
|
Create scoped loggers for different components:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const dbLogger = logger.createScope('database');
|
||||||
|
const apiLogger = logger.createScope('api');
|
||||||
|
|
||||||
|
dbLogger.log('info', 'Executing query');
|
||||||
|
apiLogger.log('info', 'Handling request');
|
||||||
|
// Logs include scope information for filtering
|
||||||
|
```
|
||||||
|
|
||||||
|
### Minimum Log Levels
|
||||||
|
|
||||||
|
Control log verbosity per environment:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const logger = new Smartlog({
|
||||||
|
logContext: { environment: 'production' },
|
||||||
|
minimumLogLevel: 'warn' // Only warn and above in production
|
||||||
|
});
|
||||||
|
|
||||||
|
// These won't be logged in production
|
||||||
|
logger.log('debug', 'Detailed debug info');
|
||||||
|
logger.log('info', 'Regular info');
|
||||||
|
|
||||||
|
// These will be logged
|
||||||
|
logger.log('warn', 'Warning message');
|
||||||
|
logger.log('error', 'Error message');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Increment Logging
|
### Increment Logging
|
||||||
|
|
||||||
For metrics and counters:
|
Perfect for metrics and counters:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
logger.increment('info', 'api_requests', { endpoint: '/users' });
|
// Track API calls
|
||||||
|
logger.increment('info', 'api.requests', { endpoint: '/users', method: 'GET' });
|
||||||
|
logger.increment('info', 'api.requests', { endpoint: '/users', method: 'POST' });
|
||||||
|
|
||||||
|
// Track errors by type
|
||||||
|
logger.increment('error', 'payment.failed', { reason: 'insufficient_funds' });
|
||||||
|
logger.increment('error', 'payment.failed', { reason: 'card_declined' });
|
||||||
```
|
```
|
||||||
|
|
||||||
### Log Correlation
|
### Capture All Console Output
|
||||||
|
|
||||||
Correlate logs across services with correlation IDs:
|
Redirect all console.log and console.error through smartlog:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
logger.log('info', 'Request received', { userId: 'user-123' }, {
|
logger.enableConsole({
|
||||||
id: 'req-abc-123',
|
captureAll: true // Capture all console.* methods
|
||||||
type: 'service',
|
});
|
||||||
transaction: 'tx-payment-456'
|
|
||||||
|
console.log('This goes through smartlog!');
|
||||||
|
console.error('This too!');
|
||||||
|
// All console output is now structured and routed through your destinations
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🏗️ Real-World Examples
|
||||||
|
|
||||||
|
### Microservice with Distributed Tracing
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Smartlog } from '@push.rocks/smartlog';
|
||||||
|
import { SmartlogDestinationClickhouse } from '@push.rocks/smartlog/destination-clickhouse';
|
||||||
|
|
||||||
|
// Initialize logger with service context
|
||||||
|
const logger = new Smartlog({
|
||||||
|
logContext: {
|
||||||
|
company: 'TechCorp',
|
||||||
|
companyunit: 'Platform',
|
||||||
|
containerName: 'user-service',
|
||||||
|
environment: process.env.NODE_ENV,
|
||||||
|
runtime: 'node',
|
||||||
|
zone: process.env.CLOUD_ZONE
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add ClickHouse for analytics
|
||||||
|
const clickhouse = await SmartlogDestinationClickhouse.createAndStart({
|
||||||
|
host: process.env.CLICKHOUSE_HOST,
|
||||||
|
database: 'microservices_logs'
|
||||||
|
});
|
||||||
|
logger.addLogDestination(clickhouse);
|
||||||
|
|
||||||
|
// Enable local console for development
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
logger.enableConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Express middleware for request tracking
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const requestId = generateRequestId();
|
||||||
|
const logGroup = logger.createLogGroup(requestId);
|
||||||
|
|
||||||
|
// Attach logger to request
|
||||||
|
req.logger = logGroup;
|
||||||
|
|
||||||
|
// Log request
|
||||||
|
logGroup.log('info', 'Incoming request', {
|
||||||
|
method: req.method,
|
||||||
|
path: req.path,
|
||||||
|
ip: req.ip
|
||||||
|
});
|
||||||
|
|
||||||
|
// Track response
|
||||||
|
res.on('finish', () => {
|
||||||
|
logGroup.log('info', 'Request completed', {
|
||||||
|
statusCode: res.statusCode,
|
||||||
|
duration: Date.now() - req.startTime
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Documentation
|
### CLI Tool with Progress Tracking
|
||||||
|
|
||||||
For detailed API documentation, see the [API.md](API.md) file.
|
```typescript
|
||||||
|
import { Smartlog } from '@push.rocks/smartlog';
|
||||||
|
import { SmartlogSourceInteractive, SmartlogProgressBar } from '@push.rocks/smartlog/source-interactive';
|
||||||
|
|
||||||
## License and Legal Information
|
const logger = new Smartlog({
|
||||||
|
logContext: {
|
||||||
|
containerName: 'migration-tool',
|
||||||
|
environment: 'cli'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.enableConsole();
|
||||||
|
|
||||||
|
async function migrateDatabase() {
|
||||||
|
const spinner = new SmartlogSourceInteractive();
|
||||||
|
|
||||||
|
// Connect to database
|
||||||
|
spinner.text('🔌 Connecting to database...');
|
||||||
|
await connectDB();
|
||||||
|
spinner.finishSuccess('✅ Connected to database');
|
||||||
|
|
||||||
|
// Get migrations
|
||||||
|
spinner.text('📋 Loading migrations...');
|
||||||
|
const migrations = await getMigrations();
|
||||||
|
spinner.finishSuccess(`✅ Found ${migrations.length} migrations`);
|
||||||
|
|
||||||
|
// Run migrations with progress bar
|
||||||
|
const progress = new SmartlogProgressBar({
|
||||||
|
total: migrations.length,
|
||||||
|
width: 40,
|
||||||
|
showEta: true
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const [index, migration] of migrations.entries()) {
|
||||||
|
logger.log('info', `Running migration: ${migration.name}`);
|
||||||
|
await runMigration(migration);
|
||||||
|
progress.update(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.complete();
|
||||||
|
logger.log('success', '🎉 All migrations completed successfully!');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Logging with Multiple Destinations
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Smartlog } from '@push.rocks/smartlog';
|
||||||
|
import { DestinationLocal } from '@push.rocks/smartlog/destination-local';
|
||||||
|
import { SmartlogDestinationFile } from '@push.rocks/smartlog/destination-file';
|
||||||
|
import { SmartlogDestinationReceiver } from '@push.rocks/smartlog/destination-receiver';
|
||||||
|
|
||||||
|
const logger = new Smartlog({
|
||||||
|
logContext: {
|
||||||
|
company: 'Enterprise Corp',
|
||||||
|
containerName: 'payment-processor',
|
||||||
|
environment: 'production',
|
||||||
|
runtime: 'node',
|
||||||
|
zone: 'us-east-1'
|
||||||
|
},
|
||||||
|
minimumLogLevel: 'info' // No debug logs in production
|
||||||
|
});
|
||||||
|
|
||||||
|
// Console for container logs (structured for log aggregators)
|
||||||
|
logger.addLogDestination(new DestinationLocal());
|
||||||
|
|
||||||
|
// File for audit trail
|
||||||
|
logger.addLogDestination(new SmartlogDestinationFile('/var/log/app/audit.log'));
|
||||||
|
|
||||||
|
// Central logging service
|
||||||
|
logger.addLogDestination(new SmartlogDestinationReceiver({
|
||||||
|
endpoint: 'https://logs.enterprise.com/ingest',
|
||||||
|
apiKey: process.env.LOG_API_KEY,
|
||||||
|
batchSize: 100,
|
||||||
|
flushInterval: 5000
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Critical error alerts
|
||||||
|
logger.addLogDestination({
|
||||||
|
async handleLog(logPackage) {
|
||||||
|
if (logPackage.level === 'error' && logPackage.data?.critical) {
|
||||||
|
await sendAlert({
|
||||||
|
channel: 'ops-team',
|
||||||
|
message: `🚨 Critical error: ${logPackage.message}`,
|
||||||
|
data: logPackage
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔌 Integration with Other Tools
|
||||||
|
|
||||||
|
### PM2 Integration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ecosystem.config.js
|
||||||
|
module.exports = {
|
||||||
|
apps: [{
|
||||||
|
name: 'api',
|
||||||
|
script: './dist/index.js',
|
||||||
|
error_file: '/dev/null', // Disable PM2 error log
|
||||||
|
out_file: '/dev/null', // Disable PM2 out log
|
||||||
|
merge_logs: true,
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
// smartlog handles all logging
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Integration
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:18-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN pnpm install --production
|
||||||
|
|
||||||
|
# smartlog handles structured logging
|
||||||
|
# No need for special log drivers
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
# Logs are structured JSON, perfect for log aggregators
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🏆 Best Practices
|
||||||
|
|
||||||
|
### 1. Use Semantic Log Levels
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ Good - semantic and meaningful
|
||||||
|
logger.log('lifecycle', 'Server starting on port 3000');
|
||||||
|
logger.log('success', 'Database connection established');
|
||||||
|
logger.log('error', 'Failed to process payment', { orderId, error });
|
||||||
|
|
||||||
|
// ❌ Bad - everything is 'info'
|
||||||
|
logger.log('info', 'Server starting');
|
||||||
|
logger.log('info', 'Database connected');
|
||||||
|
logger.log('info', 'Error: payment failed');
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Include Structured Data
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ Good - structured data for analysis
|
||||||
|
logger.log('error', 'API request failed', {
|
||||||
|
endpoint: '/api/users',
|
||||||
|
statusCode: 500,
|
||||||
|
duration: 1234,
|
||||||
|
userId: 'usr_123',
|
||||||
|
errorCode: 'INTERNAL_ERROR'
|
||||||
|
});
|
||||||
|
|
||||||
|
// ❌ Bad - data embedded in message
|
||||||
|
logger.log('error', `API request to /api/users failed with 500 in 1234ms for user usr_123`);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Use Log Groups for Correlation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ Good - correlated logs
|
||||||
|
async function processOrder(orderId: string) {
|
||||||
|
const logGroup = logger.createLogGroup(orderId);
|
||||||
|
|
||||||
|
logGroup.log('info', 'Processing order');
|
||||||
|
logGroup.log('debug', 'Validating items');
|
||||||
|
logGroup.log('info', 'Charging payment');
|
||||||
|
logGroup.log('success', 'Order processed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ Bad - no correlation
|
||||||
|
async function processOrder(orderId: string) {
|
||||||
|
logger.log('info', `Processing order ${orderId}`);
|
||||||
|
logger.log('debug', `Validating items for ${orderId}`);
|
||||||
|
logger.log('info', `Charging payment for ${orderId}`);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Environment-Specific Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ Good - different configs per environment
|
||||||
|
const logger = new Smartlog({
|
||||||
|
logContext: {
|
||||||
|
environment: process.env.NODE_ENV,
|
||||||
|
// ... other context
|
||||||
|
},
|
||||||
|
minimumLogLevel: process.env.NODE_ENV === 'production' ? 'info' : 'silly'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add destinations based on environment
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
logger.addLogDestination(clickhouseDestination);
|
||||||
|
logger.addLogDestination(alertingDestination);
|
||||||
|
} else {
|
||||||
|
logger.enableConsole();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📖 API Reference
|
||||||
|
|
||||||
|
### Smartlog Class
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class Smartlog {
|
||||||
|
constructor(options?: ISmartlogOptions)
|
||||||
|
|
||||||
|
// Logging methods
|
||||||
|
log(level: TLogLevel, message: string, data?: any, correlation?: ILogCorrelation): void
|
||||||
|
increment(level: TLogLevel, key: string, data?: any): void
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
enableConsole(options?: IConsoleOptions): void
|
||||||
|
addLogDestination(destination: ILogDestination): void
|
||||||
|
addLogContext(context: Partial<ILogContext>): void
|
||||||
|
|
||||||
|
// Log groups
|
||||||
|
createLogGroup(transactionId?: string): LogGroup
|
||||||
|
createScope(scopeName: string): Smartlog
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Log Levels
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type TLogLevel =
|
||||||
|
| 'silly' // Very verbose debugging
|
||||||
|
| 'debug' // Debug information
|
||||||
|
| 'info' // Informational messages
|
||||||
|
| 'note' // Notable events
|
||||||
|
| 'ok' // Success confirmation
|
||||||
|
| 'success' // Major success
|
||||||
|
| 'warn' // Warning messages
|
||||||
|
| 'error' // Error messages
|
||||||
|
| 'lifecycle' // Application lifecycle events
|
||||||
|
```
|
||||||
|
|
||||||
|
### Log Package Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ILogPackage {
|
||||||
|
timestamp: number;
|
||||||
|
level: TLogLevel;
|
||||||
|
message: string;
|
||||||
|
data?: any;
|
||||||
|
context: ILogContext;
|
||||||
|
correlation?: ILogCorrelation;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For complete API documentation, see [API.md](API.md).
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
|
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
||||||
|
|
||||||
|
## 📄 License and Legal Information
|
||||||
|
|
||||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||||
|
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartlog',
|
name: '@push.rocks/smartlog',
|
||||||
version: '3.1.5',
|
version: '3.1.9',
|
||||||
description: 'A minimalistic, distributed, and extensible logging tool supporting centralized log management.'
|
description: 'A minimalistic, distributed, and extensible logging tool supporting centralized log management.'
|
||||||
}
|
}
|
||||||
|
@@ -93,8 +93,8 @@ export class DestinationLocal implements ILogDestination {
|
|||||||
textColor: 'blue',
|
textColor: 'blue',
|
||||||
},
|
},
|
||||||
debug: {
|
debug: {
|
||||||
prefix: plugins.consolecolor.coloredString(' debug ', 'gray', 'black') + ' ',
|
prefix: plugins.consolecolor.coloredString(' debug ', 'pink', 'black') + ' ',
|
||||||
textColor: 'gray',
|
textColor: 'pink',
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
prefix:
|
prefix:
|
||||||
|
Reference in New Issue
Block a user