Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
e133da8076 | |||
d502ab8cc9 | |||
d1c05fb9ae | |||
f81971d148 | |||
aa6a27970a | |||
b31d9f0c36 | |||
e6cef68a26 | |||
aa327efeac | |||
7cbc64ed8d | |||
2c49ef49c2 |
32
changelog.md
32
changelog.md
@@ -1,5 +1,37 @@
|
|||||||
# 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)
|
||||||
|
Maintain and verify project metadata and commit info consistency
|
||||||
|
|
||||||
|
- No code changes; confirming commit info files and documentation remain aligned
|
||||||
|
- Ensured consistent versioning across submodules and package metadata
|
||||||
|
|
||||||
## 2025-05-20 - 3.1.4 - fix(DestinationLocal)
|
## 2025-05-20 - 3.1.4 - fix(DestinationLocal)
|
||||||
Fix debug log rendering, add fallback for unknown log levels, and correct error prefix typo in local destination
|
Fix debug log rendering, add fallback for unknown log levels, and correct error prefix typo in local destination
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartlog",
|
"name": "@push.rocks/smartlog",
|
||||||
"version": "3.1.4",
|
"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
822
readme.md
822
readme.md
@@ -1,288 +1,736 @@
|
|||||||
# @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),
|
|
||||||
level: logPackage.level,
|
// All logs in the group share the same correlation ID
|
||||||
message: logPackage.message,
|
```
|
||||||
data: logPackage.data,
|
|
||||||
context: logPackage.context
|
## 🎯 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,
|
||||||
|
message: logPackage.message,
|
||||||
|
context: logPackage.context,
|
||||||
|
data: logPackage.data,
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartlog',
|
name: '@push.rocks/smartlog',
|
||||||
version: '3.1.4',
|
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