Overview
Exulu uses Winston for structured logging across all components, including the Express server, MCP server, and worker instances. The logging system is centralized through a logger factory function that creates Winston logger instances with conditional OpenTelemetry integration.Architecture
The logging system is built around a centralized logger factory insrc/exulu/logger.ts that creates Winston logger instances with:
- Structured JSON logging: All logs are formatted as JSON with timestamps and metadata
- Error stack traces: Automatic stack trace capture for error objects
- Environment context: Automatic service name and environment labeling
- Conditional OpenTelemetry: OTel transport enabled based on configuration
- Console fallback: Always includes console transport for development
- Instance-level control: Express, Workers, and MCP can have independent telemetry settings
Logger configuration
Core logger setup
ThecreateLogger function accepts an enableOtel boolean parameter to conditionally enable OpenTelemetry transport:
Implementation details
The logger is configured with the following Winston setup:Configuration-driven telemetry
TheExuluApp class manages telemetry configuration through the ExuluConfig type:
Integration points
Express server logging
In your Express application, the logger is automatically created and configured:createExpressRoutes() for use throughout the Express application.
Example usage in routes:
BullMQ workers logging
Workers create their own logger instance with independent telemetry configuration:- Enable telemetry for production workers while keeping it off in development
- Have different logging configurations for different worker types
- Control logging overhead independently from the main application
MCP server logging
The MCP server receives the logger instance via dependency injection:Usage examples
Basic configuration
Configure telemetry in your ExuluApp config:Environment-specific logging
Different settings for development, staging, and production:Structured logging best practices
Log levels
Winston supports the following log levels (in order of priority):error- Error events that might still allow the application to continuewarn- Warning events that indicate potential issuesinfo- Informational messages highlighting application progresshttp- HTTP request/response loggingverbose- More detailed informational messagesdebug- Detailed debugging informationsilly- Most detailed logging (rarely used)
debug, which includes all levels except silly.
Setting log levels
OpenTelemetry integration
When OpenTelemetry is enabled, logs are automatically correlated with traces:Benefits of OTel integration
Trace correlation
Logs are automatically linked to active traces
Context propagation
Trace IDs and span IDs included in log metadata
Unified observability
View logs and traces together in SigNoz
Debugging workflow
Jump from trace to related logs and vice versa
Viewing logs in SigNoz
After enabling OTel logging, visit your SigNoz dashboard to:- View logs in the Logs Explorer
- Filter logs by trace ID, span ID, or custom attributes
- Jump from a trace span to related logs
- Search logs using structured query language
Performance considerations
Console vs OpenTelemetry
- Console transport: Synchronous, low overhead, good for development
- OpenTelemetry transport: Asynchronous, batched export, minimal production overhead
Batching and buffering
Logs are batched when using OpenTelemetry:- Batch size: 512 log records
- Batch interval: 1 second
- This minimizes network overhead and improves performance
Production best practices
Enable debug-level logging only in development. Use info or warn level in production to reduce log volume.
Troubleshooting
Logs not appearing in SigNoz
Check telemetry configuration
Check telemetry configuration
Verify that telemetry is enabled in your config:
Verify environment variables
Verify environment variables
Ensure OpenTelemetry environment variables are set:Should be:
- SigNoz Cloud:
https://ingest.{region}.signoz.cloud:443/v1/logs - Self-hosted:
http://localhost:4318/v1/logs
Check logger initialization
Check logger initialization
Ensure the logger is created with OpenTelemetry enabled:
Review console output
Review console output
Check if logs appear in console but not in SigNoz. This indicates a transport issue, not a logging issue.
High log volume
If you’re generating too many logs:- Increase log level to
infoorwarnin production - Use sampling for high-frequency operations
- Disable debug logging for specific components
- Use filters in SigNoz to focus on important logs
Log format issues
If logs aren’t properly structured:- Always pass objects as the second parameter to logger methods
- Use consistent field names across your application
- Avoid string interpolation in log messages
- Use the metadata format for structured data
Example log outputs
Console output (development)
OpenTelemetry output (production)
The same log with trace correlation:Best practices summary
Structure your logs
Use objects for log metadata, not string concatenation
Use appropriate levels
error for errors, warn for warnings, info for important events
Add context
Include relevant IDs, timestamps, and operation details
Enable in production
Use OTel integration for production observability
Protect sensitive data
Never log passwords, tokens, or PII
Keep it consistent
Use the same field names across your application