@syntrojs/logger
v0.2.4-alpha
Published
๐ฅ Fast, simple, and developer-friendly logger for Node.js and Bun (ALPHA - Proof of Concept)
Maintainers
Readme
Quality & Security:
Code Coverage:
โ ๏ธ ALPHA VERSION
๐จ This is an ALPHA version and proof of concept. Do not use in production!
- โ Core functionality works - All transports, child loggers, and async context.
- โ Well tested - 93.05% code coverage, 54.47% mutation score.
- โ ๏ธ API may change - Breaking changes are expected.
- โ ๏ธ Not production-ready - Missing CI/CD and stability improvements.
๐ฏ What is @syntrojs/logger?
@syntrojs/logger is a fast, simple, and developer-friendly logger for Node.js and Bun. It's designed for high performance and flexibility, offering beautiful, structured output with minimal configuration.
It works as a standalone library in any project or integrates seamlessly with the SyntroJS framework for automatic request correlation.
โจ Core Features
- โก Blazing Fast: Optimized for performance (~75% of Pino's speed).
- ๐จ Beautiful & Flexible Output: Four built-in transports (JSON, Pretty, Compact, Classic).
- ๐ง Type-Safe: Full TypeScript support out of the box.
- ๐ชถ Lightweight: Minimal dependencies (only
chalkfor colors). - ๐ฏ Simple & Fluent API: Chain methods to add rich, structured context to your logs.
- ๐๏ธ Compliance & Business Ready: Attach deeply nested metadata for compliance (GDPR, HIPAA, PCI), business analytics, or internal workflows.
- ๐ Dual Runtime: Works on both Node.js and Bun.
๐ Quick Start
1. Installation
npm install @syntrojs/logger@alpha
# or
pnpm add @syntrojs/logger@alpha2. Basic Usage
Create a logger and start logging. It's that simple.
import { createLogger } from '@syntrojs/logger';
// Create a new logger instance
const logger = createLogger({ name: 'my-app' });
logger.info('Hello, world!');
logger.info({ userId: 123 }, 'User logged in');For a shared, singleton instance across your application, use getLogger:
import { getLogger } from '@syntrojs/logger/registry';
// Gets or creates a shared logger for 'my-app'
const logger = getLogger('my-app');
logger.info('This message comes from a shared logger instance.');3. Transports for Development vs. Production
Switch between human-readable logs in development and machine-readable JSON in production with a single option.
Development (pretty):
Beautiful, colored output is the default.
const devLogger = createLogger({ name: 'dev-server', level: 'debug' });
devLogger.info({ userId: 123 }, 'User logged in');Output:
[2025-01-01T12:00:00.000Z] [INFO] (dev-server): User logged in
{
"userId": 123
}Production (json):
Structured JSON is essential for log aggregation systems.
const prodLogger = createLogger({ name: 'my-api', transport: 'json' });
prodLogger.info({ method: 'GET', path: '/users' }, 'Request received');Output:
{"time":"2025-01-01T12:00:00.000Z","level":"info","message":"Request received","service":"my-api","method":"GET","path":"/users"}๐ ๏ธ Advanced Usage: The Fluent API for Rich Context
Add contextual data to your logs easily by chaining methods.
Child Loggers & Basic Context
Create specialized loggers that automatically include context like a module name, source, or a transaction ID for distributed tracing.
const logger = createLogger({ name: 'app' });
// Create a child logger with a 'module' binding
const dbLogger = logger.child({ module: 'database' });
dbLogger.info('Connected to database'); // Log includes "module": "database"
// Chain methods to add a source and transaction ID
const requestLogger = logger
.withSource('payment-api')
.withTransactionId('tx-payment-123');
requestLogger.info('Processing payment'); // Log includes source and transactionIdThe Power of withRetention(): Compliance & Business Metadata
The .withRetention() method is the library's superpower. It allows you to attach any deeply nested JSON object to your logs. This is perfect for satisfying complex requirements for compliance, business analytics, and operations.
Why is this critical?
- Compliance: Embed data for GDPR, HIPAA, PCI-DSS, etc., to track retention policies, audit trails, and data processing rules.
- Business: Track marketing campaigns, user segments, product tiers, and other business-critical information.
- Operations: Include team ownership, monitoring metrics, workflow stages, and alert configurations.
Example: Enterprise-Grade Logging
Hereโs a logger configured for a payment service, embedding rich metadata for compliance, business, and internal monitoring.
import { createLogger } from '@syntrojs/logger';
const enterpriseLogger = createLogger({ name: 'payment-service' })
.withRetention({
// 1. Compliance Metadata (for auditors and legal)
compliance: {
regulations: {
pci: {
version: '3.2.1',
level: 1,
requirements: { encryption: 'AES-256', audit: { enabled: true, retention: '5-years' } }
},
gdpr: {
articles: [6, 7, 32],
dataProcessing: { legalBasis: 'contract', consent: 'explicit' }
}
}
},
// 2. Business Context (for analytics and product teams)
business: {
product: { id: 'payment-gateway', tier: 'enterprise' },
vendor: { primary: 'stripe', backup: 'paypal' }
},
// 3. Operational Data (for engineering and SREs)
internal: {
team: { name: 'payments-engineering' },
monitoring: { metrics: ['transaction-volume', 'error-rate', 'latency-p95'] }
}
});
// All logs from this logger will automatically include the full nested metadata
enterpriseLogger
.withTransactionId('tx-payment-12345')
.info({ amount: 299.99, currency: 'USD' }, 'Payment processed');The resulting JSON log contains the info message and payload, plus the entire retention object with all its nested compliance, business, and internal data.
Managing Multiple Configurations with a Registry
For complex applications, you can define several logger configurations in a central registry and retrieve them on demand.
import { createLogger } from '@syntrojs/logger';
const loggerRegistry = {
'simple': createLogger({ name: 'simple-app' }),
'analytics': createLogger({ name: 'analytics-service' }).withRetention({
compliance: { privacy: { gdpr: { anonymization: 'required' } } },
business: { campaigns: { active: [{ id: 'summer-2024' }] } }
}),
'enterprise': enterpriseLogger // from the example above
};
function getLogger(name: 'simple' | 'analytics' | 'enterprise') {
return loggerRegistry[name];
}
// Use loggers on-demand
getLogger('simple').info('User logged in');
getLogger('analytics').info({ event: 'purchase' }, 'Analytics event tracked');
getLogger('enterprise').withTransactionId('tx-abc').info('Enterprise log');๐จ Transports
Other Built-in Transports
Besides pretty and json, the logger includes:
compact: A single-line format perfect for CI/CD pipelines.classic: A traditional Log4j-style format.
const logger = createLogger({ transport: 'compact' });
logger.info('Request processed', { statusCode: 200, latency: 45 });
// Output: [2025-01-01T12:00:00.000Z] [INFO] (ci-pipeline): Request processed | statusCode=200 latency=45Composite Transport: Multiple Outputs
Send logs to multiple destinations at once, such as the console during development and a file for persistence.
import { createLogger, JsonTransport, PrettyTransport, CompositeTransport } from '@syntrojs/logger';
const logger = createLogger({
name: 'my-app',
transport: new CompositeTransport([
new JsonTransport(), // For log aggregation
new PrettyTransport() // For the developer console
])
});
logger.info('This appears in both JSON and pretty format');Custom Transports
You can easily create your own transport to send logs anywhere (e.g., a file, a webhook, or a monitoring service).
import { Transport, type LogEntry } from '@syntrojs/logger';
import * as fs from 'node:fs';
class FileTransport extends Transport {
private logFile: string = './logs/app.log';
log(entry: LogEntry): void {
const line = JSON.stringify(entry) + '\n';
fs.appendFileSync(this.logFile, line);
}
}
const logger = createLogger({
name: 'my-app',
transport: new FileTransport()
});
logger.info('This log will be written to ./logs/app.log');๐ API Reference
Logger Creation
createLogger(options): Creates a new, independent logger instance.getLogger(name, options?): Retrieves or creates a shared, singleton logger instance from a global registry.
Logger Options
name(string): Service/application identifier.level(string): Minimum log level to output (trace,debug,info,warn,error,fatal,silent). Default:info.transport(string | Transport): Output format (pretty,json,compact,classic) or a custom transport instance. Default:pretty.
Logger Methods
logger.info(obj?, msg?, ...args): Logs an informational message.logger.debug(...),logger.warn(...),logger.error(...), etc.logger.child(bindings): Creates a new logger that inherits from the parent and includes the providedbindingsobject in all its logs.logger.withSource(source): Returns a new logger instance with asourcefield.logger.withTransactionId(id): Returns a new logger instance with atransactionIdfield.logger.withRetention(rules): Returns a new logger instance with aretentionfield containing the provided metadata object.
๐ License
Apache 2.0 - See LICENSE for details.
