fix(destination-receiver): return full webrequest response from SmartlogDestinationReceiver and migrate to WebrequestClient; update tests, dependencies, docs, and npmextra metadata

This commit is contained in:
2026-02-14 15:52:57 +00:00
parent 2d9a8e08f2
commit 0593c3e2d0
8 changed files with 2824 additions and 1886 deletions

View File

@@ -1,5 +1,15 @@
# Changelog
## 2026-02-14 - 3.1.11 - fix(destination-receiver)
return full webrequest response from SmartlogDestinationReceiver and migrate to WebrequestClient; update tests, dependencies, docs, and npmextra metadata
- SmartlogDestinationReceiver now uses plugins.webrequest.WebrequestClient instead of plugins.webrequest.WebRequest and returns the full response object instead of response.body — callers expecting the previous shape will need to adapt (breaking change)
- Tests updated to match the new webrequest.postJson return shape
- Bumped several devDependencies and dependencies (@git.zone/* toolchain, @push.rocks/* libs) to newer major/minor versions
- Removed tsbundle from the build script and adjusted build tooling invocation
- Added pnpm.onlyBuiltDependencies and updated npmextra.json namespace keys and release/tsdoc metadata
- Documentation (readme.md) updated: examples changed to async/await usage, expanded legal and issue-reporting sections
## 2025-09-22 - 3.1.10 - fix(tests)
Bump dependency versions and adjust test to use enableConsole() default

View File

@@ -1,5 +1,5 @@
{
"gitzone": {
"@git.zone/cli": {
"projectType": "npm",
"module": {
"githost": "code.foss.global",
@@ -25,13 +25,19 @@
"error tracking",
"development tools"
]
},
"release": {
"registries": [
"https://verdaccio.lossless.digital",
"https://registry.npmjs.org"
],
"accessLevel": "public"
}
},
"npmci": {
"npmGlobalTools": [],
"npmAccessLevel": "public"
},
"tsdoc": {
"@git.zone/tsdoc": {
"legal": "\n## License and Legal Information\n\nThis 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. \n\n**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.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
},
"@ship.zone/szci": {
"npmGlobalTools": []
}
}

View File

@@ -37,28 +37,28 @@
"license": "MIT",
"scripts": {
"test": "(tstest test/**/*.ts --verbose)",
"build": "(tsbuild tsfolders --allowimplicitany && tsbundle npm)",
"build": "(tsbuild tsfolders)",
"format": "(gitzone format)",
"buildDocs": "tsdoc"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.6.8",
"@git.zone/tsbundle": "^2.5.1",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^2.3.6",
"@git.zone/tsbuild": "^4.1.2",
"@git.zone/tsbundle": "^2.8.3",
"@git.zone/tsrun": "^2.0.1",
"@git.zone/tstest": "^3.1.8",
"@types/node": "^22.15.20"
},
"dependencies": {
"@api.global/typedrequest-interfaces": "^3.0.19",
"@push.rocks/consolecolor": "^2.0.3",
"@push.rocks/isounique": "^1.0.4",
"@push.rocks/isounique": "^1.0.5",
"@push.rocks/smartclickhouse": "^2.0.17",
"@push.rocks/smartfile": "^11.2.7",
"@push.rocks/smarthash": "^3.2.3",
"@push.rocks/smarthash": "^3.2.6",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smarttime": "^4.1.1",
"@push.rocks/webrequest": "^3.0.37",
"@tsclass/tsclass": "^9.2.0"
"@push.rocks/webrequest": "^4.0.1",
"@tsclass/tsclass": "^9.3.0"
},
"files": [
"ts/**/*",
@@ -86,6 +86,10 @@
"url": "https://code.foss.global/push.rocks/smartlog/issues"
},
"pnpm": {
"overrides": {}
"overrides": {},
"onlyBuiltDependencies": [
"esbuild",
"puppeteer"
]
}
}

4019
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

628
readme.md
View File

@@ -6,10 +6,14 @@
> **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. 🎯
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## 🌟 Why smartlog?
- **🎨 Beautiful Console Output**: Color-coded, formatted logs that are actually readable
- **🔌 Extensible Architecture**: Plug in any destination - databases, files, remote servers
- **🔌 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
@@ -24,9 +28,6 @@ pnpm add @push.rocks/smartlog
# Using npm
npm install @push.rocks/smartlog
# Using yarn
yarn add @push.rocks/smartlog
```
## 🚀 Quick Start
@@ -48,25 +49,32 @@ const logger = new Smartlog({
}
});
// Enable beautiful console output
// Enable console output
logger.enableConsole();
// Start logging!
logger.log('info', '🎉 Application started successfully');
logger.log('error', '💥 Database connection failed', {
await logger.log('info', '🎉 Application started successfully');
await logger.log('error', '💥 Database connection failed', {
errorCode: 'DB_TIMEOUT',
attemptCount: 3
attemptCount: 3
});
```
### Using the Default Logger
### Using `createForCommitinfo`
For quick prototyping and simple applications:
If you're integrating with a build system that provides commit info, you can use the static factory method:
```typescript
import { defaultLogger } from '@push.rocks/smartlog';
import { Smartlog } from '@push.rocks/smartlog';
defaultLogger.log('info', 'This is so easy!');
const logger = Smartlog.createForCommitinfo({
name: 'my-app',
version: '1.0.0',
description: 'My application'
});
logger.enableConsole();
await logger.log('lifecycle', '🔄 App starting...');
```
## 📚 Core Concepts
@@ -77,25 +85,42 @@ smartlog supports semantic log levels for different scenarios:
```typescript
// Lifecycle events
logger.log('lifecycle', '🔄 Container starting up...');
await logger.log('lifecycle', '🔄 Container starting up...');
// Success states
logger.log('success', '✅ Payment processed');
logger.log('ok', '👍 Health check passed');
await logger.log('success', '✅ Payment processed');
await logger.log('ok', '👍 Health check passed');
// Information and debugging
logger.log('info', '📋 User profile updated');
logger.log('note', '📌 Cache invalidated');
logger.log('debug', '🔍 Query execution plan', { sql: 'SELECT * FROM users' });
await logger.log('info', '📋 User profile updated');
await logger.log('note', '📌 Cache invalidated');
await 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');
await logger.log('warn', '⚠️ Memory usage above 80%');
await logger.log('error', '❌ Failed to send email');
// Verbose output
logger.log('silly', '🔬 Entering function processPayment()');
await logger.log('silly', '🔬 Entering function processPayment()');
```
Available levels (from most to least verbose): `silly`, `debug`, `info`, `note`, `ok`, `success`, `warn`, `error`, `lifecycle`
### Log Types
Each log entry has a type that describes what kind of data it represents:
| Type | Description |
|------|-------------|
| `log` | Standard log message |
| `increment` | Counter/metric increment |
| `gauge` | Gauge measurement |
| `error` | Error event |
| `success` | Success event |
| `value` | Value recording |
| `finance` | Financial transaction |
| `compliance` | Compliance event |
### Log Groups for Correlation
Perfect for tracking request flows through your system:
@@ -109,36 +134,75 @@ requestGroup.log('debug', 'Validating request body');
requestGroup.log('info', 'Creating user in database');
requestGroup.log('success', 'User created successfully', { userId: 'usr_123' });
// All logs in the group share the same correlation ID
// All logs in the group share the same group ID and transaction ID
```
### Log Context
Every log carries contextual information about the environment it was created in:
```typescript
interface ILogContext {
commitinfo?: ICommitInfo; // Build/version info
company?: string; // Company name
companyunit?: string; // Team or department
containerName?: string; // Container/service name
environment?: 'local' | 'test' | 'staging' | 'production';
runtime?: 'node' | 'chrome' | 'rust' | 'deno' | 'cloudflare_workers';
zone?: string; // Deployment zone/region
}
```
## 🎯 Log Destinations
smartlog routes log packages to any number of destinations simultaneously. Each destination implements the `ILogDestination` interface with a single `handleLog` method.
### Built-in Destinations
#### 🖥️ Local Console (Enhanced)
Beautiful, colored output for local development:
Beautiful, color-coded 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
});
const localDestination = new DestinationLocal();
logger.addLogDestination(localDestination);
// Output is color-coded per log level:
// 🔵 info: blue prefix, white text
// 🔴 error: red prefix, red text
// 🟢 ok/success: green prefix, green text
// 🟠 warn: orange prefix, orange text
// 🟣 note/debug: pink prefix, pink text
// 🔵 silly: blue background, blue text
```
The `DestinationLocal` also supports **reduced logging** — a mode where repeated identical log messages are suppressed:
```typescript
const localDest = new DestinationLocal();
localDest.logReduced('Waiting for connection...'); // Logged
localDest.logReduced('Waiting for connection...'); // Suppressed
localDest.logReduced('Waiting for connection...'); // Suppressed
localDest.logReduced('Connected!'); // Logged (new message)
```
#### 📁 File Logging
Persist logs to files with automatic rotation support:
Persist logs to files with timestamped entries:
```typescript
import { SmartlogDestinationFile } from '@push.rocks/smartlog/destination-file';
const fileDestination = new SmartlogDestinationFile('./logs/app.log');
// Path MUST be absolute
const fileDestination = new SmartlogDestinationFile('/var/log/myapp/app.log');
logger.addLogDestination(fileDestination);
// Log entries are written as timestamped lines:
// 2024-01-15T10:30:00.000Z: Application started
// 2024-01-15T10:30:01.123Z: Processing request
```
#### 🌐 Browser DevTools
@@ -150,60 +214,54 @@ import { SmartlogDestinationDevtools } from '@push.rocks/smartlog/destination-de
const devtools = new SmartlogDestinationDevtools();
logger.addLogDestination(devtools);
// Uses CSS styling in browser console for beautiful, categorized output
// Different colors for error (red), info (pink), ok (green), success (green),
// warn (orange), and note (blue) levels
```
#### 📊 ClickHouse Analytics
Store logs in ClickHouse for powerful analytics:
Store logs in ClickHouse for powerful time-series analytics:
```typescript
import { SmartlogDestinationClickhouse } from '@push.rocks/smartlog/destination-clickhouse';
const clickhouse = await SmartlogDestinationClickhouse.createAndStart({
host: 'analytics.example.com',
port: 8123,
url: 'https://analytics.example.com:8123',
database: 'logs',
user: 'logger',
username: '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:
Send logs to a centralized logging service with authenticated transport:
```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
passphrase: process.env.LOG_PASSPHRASE,
receiverEndpoint: 'https://logs.mycompany.com/ingest'
});
logger.addLogDestination(receiver);
```
Logs are sent as authenticated JSON payloads with SHA-256 hashed passphrases.
### 🛠️ Custom Destinations
Build your own destination for any logging backend:
Build your own destination for any logging backend by implementing the `ILogDestination` interface:
```typescript
import { ILogDestination, ILogPackage } from '@push.rocks/smartlog/interfaces';
import type { 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]}`,
@@ -219,10 +277,7 @@ class ElasticsearchDestination implements ILogDestination {
}
}
// Use your custom destination
logger.addLogDestination(new ElasticsearchDestination({
node: 'https://elasticsearch.example.com'
}));
logger.addLogDestination(new ElasticsearchDestination());
```
## 🎨 Interactive Console Features
@@ -241,19 +296,20 @@ 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!');
// Chain success and move to next task
spinner.text('📡 Connecting to database');
// ... connect
spinner.successAndNext('🔍 Running migrations');
// ... migrate
spinner.finishSuccess('🎉 Database ready!');
// Customize appearance
spinner
.setSpinnerStyle('dots') // dots, line, star, simple
.setSpinnerStyle('dots') // 'dots' | 'line' | 'star' | 'simple'
.setColor('cyan') // any terminal color
.setSpeed(80) // animation speed in ms
.text('🚀 Deploying application...');
.setSpeed(80); // animation speed in ms
spinner.text('🚀 Deploying application...');
// Handle failures
try {
@@ -274,12 +330,12 @@ import { SmartlogProgressBar } from '@push.rocks/smartlog/source-interactive';
// Create a progress bar
const progress = new SmartlogProgressBar({
total: 100,
width: 40,
complete: '█',
incomplete: '░',
showEta: true,
showPercent: true,
showCount: true
width: 40, // Bar width in characters
complete: '█', // Fill character
incomplete: '░', // Empty character
showEta: true, // Show estimated time remaining
showPercent: true, // Show percentage
showCount: true // Show current/total count
});
// Update progress
@@ -290,22 +346,21 @@ for (let i = 0; i <= 100; i++) {
progress.complete();
// Real-world example: Processing files
// Or use increment for simpler tracking
const files = await getFiles();
const progress = new SmartlogProgressBar({
total: files.length,
width: 50
});
const fileProgress = new SmartlogProgressBar({ total: files.length });
for (const [index, file] of files.entries()) {
for (const file of files) {
await processFile(file);
progress.increment(); // or progress.update(index + 1)
fileProgress.increment();
}
fileProgress.complete();
```
### Non-Interactive Fallback
Both spinners and progress bars automatically detect non-interactive environments (CI/CD, Docker logs, piped output) and fallback to simple text output:
Both spinners and progress bars automatically detect non-interactive environments (CI/CD, Docker logs, piped output) and fall back to simple text output:
```
[Loading] Connecting to database
@@ -314,86 +369,96 @@ Both spinners and progress bars automatically detect non-interactive environment
Progress: 25% (25/100)
Progress: 50% (50/100)
Progress: 100% (100/100)
[Success] Migrations complete
Completed: 100% (100/100)
```
Detection checks for: TTY capability, CI environment variables (GitHub Actions, Jenkins, GitLab CI, Travis, CircleCI), and `TERM=dumb`.
### Backward Compatibility
The `SmartlogSourceOra` class extends `SmartlogSourceInteractive` and provides a compatibility layer for code that previously used the `ora` npm package:
```typescript
import { SmartlogSourceOra } from '@push.rocks/smartlog/source-interactive';
const ora = new SmartlogSourceOra();
ora.oraInstance.start();
ora.oraInstance.succeed('Done!');
```
## 🔧 Advanced Features
### Context Management
### Minimum Log Level
Add context that flows through your entire application:
```typescript
// 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:
Set a minimum log level that destinations can use to filter messages:
```typescript
const logger = new Smartlog({
logContext: { environment: 'production' },
minimumLogLevel: 'warn' // Only warn and above in production
logContext: { environment: 'production', runtime: 'node' },
minimumLogLevel: 'warn' // Destinations can check this to filter
});
// 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');
// The minimumLogLevel is available as a public property
console.log(logger.minimumLogLevel); // 'warn'
```
### Increment Logging
Perfect for metrics and counters:
Track metrics and counters alongside your logs:
```typescript
// 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
// Track error types
logger.increment('error', 'payment.failed', { reason: 'insufficient_funds' });
logger.increment('error', 'payment.failed', { reason: 'card_declined' });
```
Increment logs are routed to all destinations with `type: 'increment'` so analytics backends can aggregate them.
### Capture All Console Output
Redirect all console.log and console.error through smartlog:
Redirect all `console.log` and `console.error` through smartlog:
```typescript
logger.enableConsole({
captureAll: true // Capture all console.* methods
logger.enableConsole({
captureAll: true
});
console.log('This goes through smartlog!');
console.error('This too!');
// All console output is now structured and routed through your destinations
console.log('This goes through smartlog as info!');
console.error('This goes through smartlog as error!');
// Strings containing "Error:" are automatically classified as error level
// All captured output is prefixed with "LOG =>" to prevent recursion
```
### Log Receiver Server
Accept authenticated log packages from remote services:
```typescript
import { SmartlogReceiver } from '@push.rocks/smartlog/receiver';
const receiver = new SmartlogReceiver({
smartlogInstance: logger,
passphrase: 'shared-secret',
validatorFunction: async (logPackage) => {
// Custom validation logic
return logPackage.context.company === 'MyCompany';
}
});
// Handle incoming authenticated log packages (e.g., from an HTTP endpoint)
app.post('/logs', async (req, res) => {
const result = await receiver.handleAuthenticatedLog(req.body);
res.json(result); // { status: 'ok' } or { status: 'error' }
});
// Or handle batches
app.post('/logs/batch', async (req, res) => {
await receiver.handleManyAuthenticatedLogs(req.body);
res.json({ status: 'ok' });
});
```
## 🏗️ Real-World Examples
@@ -403,6 +468,7 @@ console.error('This too!');
```typescript
import { Smartlog } from '@push.rocks/smartlog';
import { SmartlogDestinationClickhouse } from '@push.rocks/smartlog/destination-clickhouse';
import { DestinationLocal } from '@push.rocks/smartlog/destination-local';
// Initialize logger with service context
const logger = new Smartlog({
@@ -410,47 +476,39 @@ const logger = new Smartlog({
company: 'TechCorp',
companyunit: 'Platform',
containerName: 'user-service',
environment: process.env.NODE_ENV,
environment: 'production',
runtime: 'node',
zone: process.env.CLOUD_ZONE
zone: 'eu-central'
}
});
// Add ClickHouse for analytics
const clickhouse = await SmartlogDestinationClickhouse.createAndStart({
host: process.env.CLICKHOUSE_HOST,
url: process.env.CLICKHOUSE_URL,
database: 'microservices_logs'
});
logger.addLogDestination(clickhouse);
// Enable local console for development
if (process.env.NODE_ENV === 'development') {
logger.enableConsole();
}
// Add local console for container stdout
logger.addLogDestination(new DestinationLocal());
// 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
const logGroup = logger.createLogGroup(req.headers['x-request-id'] || 'unknown');
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();
});
```
@@ -464,7 +522,8 @@ import { SmartlogSourceInteractive, SmartlogProgressBar } from '@push.rocks/smar
const logger = new Smartlog({
logContext: {
containerName: 'migration-tool',
environment: 'cli'
environment: 'local',
runtime: 'node'
}
});
@@ -472,32 +531,29 @@ 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 logger.log('info', `Running migration: ${migration.name}`);
await runMigration(migration);
progress.update(index + 1);
}
progress.complete();
logger.log('success', '🎉 All migrations completed successfully!');
await logger.log('success', '🎉 All migrations completed successfully!');
}
```
@@ -517,10 +573,10 @@ const logger = new Smartlog({
runtime: 'node',
zone: 'us-east-1'
},
minimumLogLevel: 'info' // No debug logs in production
minimumLogLevel: 'info'
});
// Console for container logs (structured for log aggregators)
// Color-coded console for container logs
logger.addLogDestination(new DestinationLocal());
// File for audit trail
@@ -528,221 +584,121 @@ 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
passphrase: process.env.LOG_PASSPHRASE,
receiverEndpoint: 'https://logs.enterprise.com/ingest'
}));
// Critical error alerts
// Custom inline destination for critical 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
});
await sendSlackAlert(`🚨 Critical error: ${logPackage.message}`);
}
}
});
```
## 🔌 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
// Static factory
static createForCommitinfo(commitinfo: ICommitInfo): Smartlog;
// Constructor
constructor(options: {
logContext: ILogContext;
minimumLogLevel?: TLogLevel; // default: 'silly'
});
// Logging
log(level: TLogLevel, message: string, data?: any, correlation?: ILogCorrelation): Promise<void>;
increment(level: TLogLevel, message: string, data?: any, correlation?: ILogCorrelation): 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
enableConsole(options?: { captureAll: boolean }): void;
addLogDestination(destination: ILogDestination): void;
// Correlation
createLogGroup(transactionId?: string): LogGroup;
// Forwarding (for receiver pattern)
handleLog(logPackage: ILogPackage): Promise<void>;
// Instance identity
uniInstanceId: string;
logContext: ILogContext;
minimumLogLevel: TLogLevel;
}
```
### Log Levels
### LogGroup Class
```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
```
class LogGroup {
groupId: string; // Auto-generated unique ID
transactionId: string; // The transaction ID passed at creation
smartlogRef: Smartlog; // Reference to the parent Smartlog
### Log Package Structure
```typescript
interface ILogPackage {
timestamp: number;
level: TLogLevel;
message: string;
data?: any;
context: ILogContext;
correlation?: ILogCorrelation;
log(level: TLogLevel, message: string, data?: any): void;
}
```
For complete API documentation, see [API.md](API.md).
### ILogDestination Interface
## 🤝 Contributing
```typescript
interface ILogDestination {
handleLog(logPackage: ILogPackage): Promise<void>;
}
```
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
### ILogPackage Interface
## 📄 License and Legal Information
```typescript
interface ILogPackage<T = unknown> {
timestamp: number; // Unix timestamp in milliseconds
type: TLogType; // 'log' | 'increment' | 'gauge' | ...
context: ILogContext; // Environment context
level: TLogLevel; // Log severity
correlation: ILogCorrelation; // Correlation metadata
message: string; // The log message
data?: T; // Optional structured data
}
```
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.
### Available Log Levels
| Level | Description | Use Case |
|-------|-------------|----------|
| `silly` | Ultra-verbose | Function entry/exit, variable dumps |
| `debug` | Debug info | Development-time diagnostics |
| `info` | Informational | Standard operational messages |
| `note` | Notable events | Important but non-critical events |
| `ok` | Success confirmation | Health checks, validations |
| `success` | Major success | Completed operations |
| `warn` | Warnings | Degraded performance, approaching limits |
| `error` | Errors | Failures requiring attention |
| `lifecycle` | Lifecycle events | Start, stop, restart, deploy |
## License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) 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.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
### Company Information
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

View File

@@ -53,10 +53,7 @@ tap.test('should attempt to send logs to the receiver endpoint', async () => {
// Create a mock version of the webrequest.postJson method to avoid actual HTTP calls
const originalPostJson = testDestination['webrequest'].postJson;
testDestination['webrequest'].postJson = async () => {
return {
body: { status: 'ok' },
statusCode: 200
};
return { status: 'ok' };
};
try {

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartlog',
version: '3.1.10',
version: '3.1.11',
description: 'A minimalistic, distributed, and extensible logging tool supporting centralized log management.'
}

View File

@@ -12,7 +12,7 @@ export interface ISmartlogDestinationReceiverConstructorOptions {
export class SmartlogDestinationReceiver implements ILogDestination {
private options: ISmartlogDestinationReceiverConstructorOptions;
private webrequest = new plugins.webrequest.WebRequest();
private webrequest = new plugins.webrequest.WebrequestClient();
constructor(optionsArg: ISmartlogDestinationReceiverConstructorOptions) {
this.options = optionsArg;
@@ -30,6 +30,6 @@ export class SmartlogDestinationReceiver implements ILogDestination {
}
this.errorCounter++;
});
return response.body;
return response;
}
}