
Product
Introducing Pull Request Stories to Help Security Teams Track Supply Chain Risks
Socketβs new Pull Request Stories give security teams clear visibility into dependency risks and outcomes across scanned pull requests.
syntropylog
Advanced tools
From Chaos to Clarity
The Instance Manager with Observability for High-Performance Teams
SyntropyLog is an instance manager with observability for Node.js applications. It's not just a logger - it's a complete system that manages your application instances, their connections, and provides complete observability across your entire system with zero performance overhead.
npm install syntropylog
import { syntropyLog } from 'syntropylog';
// Initialize with minimal configuration
await syntropyLog.init({
logger: {
serviceName: 'my-app',
level: 'info',
},
});
// Use it immediately
const logger = syntropyLog.getLogger();
logger.info('Hello, SyntropyLog!');
// Add this to your main application file
process.on('SIGTERM', async () => {
console.log('π Shutting down gracefully...');
await syntropyLog.shutdown();
process.exit(0);
});
process.on('SIGINT', async () => {
console.log('π Shutting down gracefully...');
await syntropyLog.shutdown();
process.exit(0);
});
β οΈ CRITICAL: You MUST include graceful shutdown in ALL applications. This ensures logs are flushed and resources are cleaned up when your application stops.
SyntropyLog CLI tools are now available as a separate package for better modularity and focused development.
npm install -g @syntropysoft/praetorian
praetorian doctor
- Diagnose your SyntropyLog configurationpraetorian init
- Initialize a new SyntropyLog projectpraetorian audit
- Audit your logging configurationpraetorian validate
- Validate configuration filesπ¦ Note: The CLI was previously included in this package but has been moved to
@syntropysoft/praetorian
for better modularity.
SyntropyLog is designed for enterprise environments and can be easily integrated into your internal infrastructure.
π Security by Default
ποΈ Scalable Architecture
β‘ Performance Excellence
// Start with a single microservice
await syntropyLog.init({
logger: {
serviceName: 'user-service',
level: 'info',
},
context: {
correlationIdHeader: 'X-Correlation-ID',
},
redis: {
instances: [{
instanceName: 'cache',
url: process.env.REDIS_URL,
}]
}
});
// Standardize across multiple services
const standardConfig = {
logger: {
level: process.env.LOG_LEVEL || 'info',
serviceName: process.env.SERVICE_NAME,
},
context: {
correlationIdHeader: 'X-Correlation-ID',
traceIdHeader: 'X-Trace-ID',
},
masking: {
fields: ['password', 'token', 'secret'],
preserveLength: true,
}
};
// Full enterprise configuration
await syntropyLog.init({
...standardConfig,
redis: {
instances: [
{ instanceName: 'cache', url: process.env.CACHE_REDIS_URL },
{ instanceName: 'session', url: process.env.SESSION_REDIS_URL },
]
},
brokers: {
instances: [
{ instanceName: 'events', adapter: new KafkaAdapter(kafkaConfig) },
{ instanceName: 'notifications', adapter: new RabbitMQAdapter(rabbitConfig) },
]
},
http: {
instances: [
{ instanceName: 'api', adapter: new AxiosAdapter(axiosConfig) },
]
}
});
// config/syntropylog.ts
export const getSyntropyConfig = (env: string) => {
const baseConfig = {
logger: {
level: process.env.LOG_LEVEL || 'info',
serviceName: process.env.SERVICE_NAME,
},
context: {
correlationIdHeader: 'X-Correlation-ID',
}
};
switch (env) {
case 'development':
return {
...baseConfig,
redis: { instances: [{ instanceName: 'cache', url: 'redis://localhost:6379' }] }
};
case 'staging':
return {
...baseConfig,
redis: { instances: [{ instanceName: 'cache', url: process.env.STAGING_REDIS_URL }] },
masking: { fields: ['password', 'token'] }
};
case 'production':
return {
...baseConfig,
redis: { instances: [{ instanceName: 'cache', url: process.env.PROD_REDIS_URL }] },
masking: { fields: ['password', 'token', 'secret', 'apiKey'] },
loggingMatrix: {
default: ['correlationId', 'serviceName'],
error: ['*']
}
};
}
};
// shared/syntropylog-setup.ts
export class SyntropyLogManager {
private static instance: SyntropyLogManager;
static getInstance(): SyntropyLogManager {
if (!SyntropyLogManager.instance) {
SyntropyLogManager.instance = new SyntropyLogManager();
}
return SyntropyLogManager.instance;
}
async initialize(serviceName: string) {
const config = getSyntropyConfig(process.env.NODE_ENV);
await syntropyLog.init({
...config,
logger: { ...config.logger, serviceName }
});
}
getLogger(context?: string) {
return syntropyLog.getLogger(context);
}
getRedis(instanceName: string) {
return syntropyLog.getRedis(instanceName);
}
}
// Add custom metrics to your logs
const logger = syntropyLog.getLogger();
logger.info('API Request', {
endpoint: '/users',
method: 'GET',
duration: 150,
statusCode: 200,
// These will be automatically picked up by your monitoring system
metrics: {
request_duration_ms: 150,
requests_total: 1,
status_code: 200
}
});
// Configure for ELK stack
await syntropyLog.init({
logger: {
serviceName: 'user-service',
level: 'info',
transports: [
new JsonConsoleTransport(), // Structured JSON for Logstash
]
},
context: {
correlationIdHeader: 'X-Correlation-ID',
}
});
// Automatic sensitive data masking
await syntropyLog.init({
masking: {
fields: ['password', 'token', 'secret', 'apiKey', 'creditCard'],
preserveLength: true, // Shows **** instead of completely hiding
patterns: [
{ regex: /\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/, replacement: '[CARD_NUMBER]' }
]
}
});
// Usage - sensitive data is automatically masked
logger.info('User login attempt', {
email: 'user@example.com',
password: 'secret123', // Will be masked as '********'
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' // Will be masked
});
// GDPR/Compliance ready logging
await syntropyLog.init({
loggingMatrix: {
default: ['correlationId', 'serviceName', 'timestamp'],
audit: ['*'], // Log everything for audit trails
error: ['*', 'stackTrace', 'context'],
security: ['*', 'ipAddress', 'userAgent', 'requestId']
}
});
// 1. Install and initialize
import { syntropyLog } from 'syntropylog';
await syntropyLog.init({
logger: { serviceName: 'tutorial-app', level: 'info' }
});
// 2. Use basic logging
const logger = syntropyLog.getLogger();
logger.info('Application started');
logger.warn('This is a warning');
logger.error('This is an error', { error: 'Something went wrong' });
// 3. Add context
logger.info('User action', { userId: '123', action: 'login' });
// 1. Set up context management
await syntropyLog.init({
logger: { serviceName: 'context-demo', level: 'info' },
context: { correlationIdHeader: 'X-Correlation-ID' }
});
// 2. Create context for a request
const contextManager = syntropyLog.getContextManager();
contextManager.run(async () => {
// Set correlation ID
contextManager.set('X-Correlation-ID', 'req-123');
const logger = syntropyLog.getLogger();
logger.info('Request started'); // Automatically includes correlation ID
// All operations in this context will have the same correlation ID
await someAsyncOperation();
logger.info('Request completed');
});
// 1. Configure Redis
await syntropyLog.init({
logger: { serviceName: 'redis-demo', level: 'info' },
context: { correlationIdHeader: 'X-Correlation-ID' },
redis: {
instances: [{
instanceName: 'cache',
url: 'redis://localhost:6379'
}]
}
});
// 2. Use Redis with automatic correlation
const redis = syntropyLog.getRedis('cache');
const logger = syntropyLog.getLogger();
// Set context
const contextManager = syntropyLog.getContextManager();
contextManager.run(async () => {
contextManager.set('X-Correlation-ID', 'user-456');
// All operations automatically include correlation ID
await redis.set('user:456:profile', JSON.stringify({ name: 'John' }));
const profile = await redis.get('user:456:profile');
logger.info('User profile cached', { userId: '456' });
});
// 1. Create custom transport
import { Transport } from 'syntropylog';
class SlackTransport extends Transport {
async log(level: string, message: string, meta: any) {
if (level === 'error') {
// Send errors to Slack
await this.sendToSlack({
text: `π¨ Error in ${meta.serviceName}: ${message}`,
attachments: [{ text: JSON.stringify(meta, null, 2) }]
});
}
}
}
// 2. Use custom transport
await syntropyLog.init({
logger: {
serviceName: 'slack-demo',
level: 'info',
transports: [
new PrettyConsoleTransport(),
new SlackTransport()
]
}
});
// 1. Configure HTTP client
import { AxiosAdapter } from '@syntropylog/adapters';
import axios from 'axios';
await syntropyLog.init({
logger: { serviceName: 'http-demo', level: 'info' },
context: { correlationIdHeader: 'X-Correlation-ID' },
http: {
instances: [{
instanceName: 'api',
adapter: new AxiosAdapter(axios.create({
baseURL: 'https://api.example.com'
}))
}]
}
});
// 2. Use instrumented HTTP client
const apiClient = syntropyLog.getHttp('api');
const logger = syntropyLog.getLogger();
// All HTTP calls automatically include correlation ID and logging
const response = await apiClient.request({
method: 'GET',
url: '/users/123'
});
logger.info('API call completed', {
statusCode: response.status,
duration: response.duration
});
SyntropyLog achieves a remarkable technical milestone: offering advanced distributed tracing and instance management capabilities with zero performance impact.
Logger | Bundle Size (JS) | Performance Time | vs No Logger | vs Pino |
---|---|---|---|---|
No Logger | 5 KB | 3 ms | - | - |
Pino | 5 KB | 2 ms | -193 B | - |
SyntropyLog | 5 KB | 2 ms | +10 B | +203 B (1.03x) / +0 ms (1.00x) |
SyntropyLog follows the "Silent Observer" principle - we report what happened and nothing more.
// β
Your application continues running, even if logging fails
try {
const result = await database.query('SELECT * FROM users');
logger.info('Query successful', { count: result.length });
} catch (error) {
// Your error handling continues normally
logger.error('Database error', { error: error.message });
// Application logic continues...
}
Think of SyntropyLog as a journalist - we observe, report, and never interfere with the main story.
await syntropyLog.init({
logger: {
serviceName: 'my-app',
level: 'info', // debug, info, warn, error
},
context: {
correlationIdHeader: 'X-Correlation-ID',
}
});
await syntropyLog.init({
logger: {
serviceName: 'my-app',
level: 'info',
transports: [
new PrettyConsoleTransport(),
new JsonConsoleTransport(),
]
},
context: {
correlationIdHeader: 'X-Correlation-ID',
traceIdHeader: 'X-Trace-ID',
},
redis: {
instances: [
{ instanceName: 'cache', url: 'redis://localhost:6379' },
{ instanceName: 'session', url: 'redis://localhost:6380' },
]
},
brokers: {
instances: [
{ instanceName: 'events', adapter: new KafkaAdapter(kafkaConfig) },
]
},
http: {
instances: [
{ instanceName: 'api', adapter: new AxiosAdapter(axiosConfig) },
]
},
masking: {
fields: ['password', 'token', 'secret'],
preserveLength: true,
},
loggingMatrix: {
default: ['correlationId', 'serviceName'],
error: ['*'],
audit: ['*'],
}
});
import { describe, it, expect, beforeEach } from 'vitest';
import { UserService } from './UserService';
const { createTestHelper } = require('syntropylog/testing');
// No initialization, no shutdown, no external dependencies
const testHelper = createTestHelper();
describe('UserService', () => {
let userService: UserService;
beforeEach(() => {
testHelper.beforeEach(); // Reset mocks
userService = new UserService(testHelper.mockSyntropyLog); // Inject mock
});
it('should create user successfully', async () => {
const result = await userService.createUser({
name: 'John',
email: 'john@example.com'
});
expect(result).toHaveProperty('userId');
expect(result.name).toBe('John');
});
});
Estos ejemplos demuestran el poder real de SyntropyLog en aplicaciones complejas del mundo real:
E-commerce API con observabilidad total
WebSocket server con analytics en tiempo real
Estos ejemplos demuestran el poder real de SyntropyLog en aplicaciones complejas del mundo real:
E-commerce API con observabilidad total
WebSocket server con analytics en tiempo real
We invite any member of the community to audit the code. If you find anything suspicious, please open an issue or a pull request.
We welcome contributions! Please see our Contributing Guide for details.
git clone https://github.com/Syntropysoft/SyntropyLog.git
cd SyntropyLog
npm install
npm run test
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
From Chaos to Clarity - Ship resilient, secure, and cost-effective Node.js applications with confidence.
Built with β€οΈ by the SyntropySoft Team
We specialize in enterprise observability solutions and custom integrations. Whether you need:
Let's discuss how SyntropyLog can enhance your observability strategy.
Empowering high-performance teams with enterprise-grade observability
Thank you for considering SyntropyLog for your mission-critical systems.
β Gabriel
FAQs
An instance manager with observability for Node.js applications
We found that syntropylog demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socketβs new Pull Request Stories give security teams clear visibility into dependency risks and outcomes across scanned pull requests.
Research
/Security News
npm author Qixβs account was compromised, with malicious versions of popular packages like chalk-template, color-convert, and strip-ansi published.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.