The best Javascript library for structured logging
Modern JavaScript applications need structured logging. As applications grow in complexity, being able to search, analyze, and monitor logs becomes critical. Yet most logging solutions make this surprisingly difficult. Traditional logging libraries in JavaScript have a fundamental problem: they were designed for string-based logging first, with structured data added as an afterthought. This leads to several critical issues in modern applications: Inconsistent Data Structure: Each log entry can have different shapes of data, making it hard to query and analyze logs at scale. Poor Type Safety: Most loggers accept any object as metadata, leading to runtime errors and inconsistent data types. Mixed Concerns: Message, data, and errors are often jumbled together, making it difficult to parse and process logs programmatically. Limited Context Support: Adding application-wide context often requires manual string concatenation or messy object merging. Inflexible APIs: Simple tasks like adding both error and metadata to a log require awkward workarounds. Let's look at how popular logging libraries handle these challenges: Winston // Mixing message and data with no clear structure winston.info("Processing order", { orderId, userId, amount }); Bunyan // Requires creating child loggers just to add context const orderLogger = logger.child({ orderId, userId }); orderLogger.info({ amount }, "Processing order"); Pino // Similar issues - metadata and message mixed together logger.info({ orderId, userId, amount }, "Processing order"); While these libraries have attempted to add structured logging capabilities, their string-first design makes them cumbersome for modern, data-driven logging needs. They each have their own way of handling structured data, but none provide a truly satisfying solution. A Better Approach to Structured Logging What if there was a logging library designed from the ground up for structured logging? One that enforced consistent log structure, provided type safety, and cleanly separated different types of data? This is where LogLayer (MIT Licensed) comes in. Here's how it handles the same logging task: // Clean separation of concerns with type-safe builder pattern logger .withContext({ userId }) // application-wide context .withMetadata({ // request-specific data orderId, amount }) .info("Processing order"); LogLayer was built from the ground up with structured logging as its core focus. It provides: Type-safe builder pattern API Clear separation between context, metadata, and messages Consistent structure across your entire application Powerful plugin system for data transformation Support for multiple transports without changing log structure First-class error handling and serialization Let's explore how LogLayer solves each of the traditional logging problems: Rich Structured Data Support LogLayer makes it easy to include structured data with your logs: // Add context that will be included with all logs logger.withContext({ service: "payment-api", version: "1.2.0" }); // Add metadata for specific log entries logger.withMetadata({ orderId: "12345", amount: 99.99 }).info("Payment processed successfully"); First-Class Error Handling Error logging is a core feature with dedicated support: try { // ... some code that might throw } catch (error) { logger.withError(error) .withMetadata({ userId: "123" }) .error("Failed to process payment"); } // Or log just the error logger.errorOnly(error); Flexible Configuration LogLayer offers extensive configuration options: Custom error serialization Configurable field names for errors, context, and metadata Enable/disable logging at runtime Multiple transport support Plugin system for extending functionality Clean Builder Pattern API The builder pattern makes the API intuitive and chainable: logger .withContext({ env: "production" }) .withMetadata({ requestId: "abc-123" }) .withError(error) .error("Operation failed"); Conclusion LogLayer brings structure and consistency to your application's logging while remaining flexible and extensible. Its rich feature set and clean API make it an excellent choice for applications that need robust, structured logging capabilities.
Modern JavaScript applications need structured logging. As applications grow in complexity, being able to search, analyze, and monitor logs becomes critical. Yet most logging solutions make this surprisingly difficult.
Traditional logging libraries in JavaScript have a fundamental problem: they were designed for string-based logging first, with structured data added as an afterthought. This leads to several critical issues in modern applications:
- Inconsistent Data Structure: Each log entry can have different shapes of data, making it hard to query and analyze logs at scale.
- Poor Type Safety: Most loggers accept any object as metadata, leading to runtime errors and inconsistent data types.
- Mixed Concerns: Message, data, and errors are often jumbled together, making it difficult to parse and process logs programmatically.
- Limited Context Support: Adding application-wide context often requires manual string concatenation or messy object merging.
- Inflexible APIs: Simple tasks like adding both error and metadata to a log require awkward workarounds.
Let's look at how popular logging libraries handle these challenges:
Winston
// Mixing message and data with no clear structure
winston.info("Processing order", { orderId, userId, amount });
Bunyan
// Requires creating child loggers just to add context
const orderLogger = logger.child({ orderId, userId });
orderLogger.info({ amount }, "Processing order");
Pino
// Similar issues - metadata and message mixed together
logger.info({ orderId, userId, amount }, "Processing order");
While these libraries have attempted to add structured logging capabilities, their string-first design makes them cumbersome for modern, data-driven logging needs. They each have their own way of handling structured data, but none provide a truly satisfying solution.
A Better Approach to Structured Logging
What if there was a logging library designed from the ground up for structured logging? One that enforced consistent log structure, provided type safety, and cleanly separated different types of data?
This is where LogLayer (MIT Licensed) comes in. Here's how it handles the same logging task:
// Clean separation of concerns with type-safe builder pattern
logger
.withContext({ userId }) // application-wide context
.withMetadata({ // request-specific data
orderId,
amount
})
.info("Processing order");
LogLayer was built from the ground up with structured logging as its core focus. It provides:
- Type-safe builder pattern API
- Clear separation between context, metadata, and messages
- Consistent structure across your entire application
- Powerful plugin system for data transformation
- Support for multiple transports without changing log structure
- First-class error handling and serialization
Let's explore how LogLayer solves each of the traditional logging problems:
Rich Structured Data Support
LogLayer makes it easy to include structured data with your logs:
// Add context that will be included with all logs
logger.withContext({
service: "payment-api",
version: "1.2.0"
});
// Add metadata for specific log entries
logger.withMetadata({
orderId: "12345",
amount: 99.99
}).info("Payment processed successfully");
First-Class Error Handling
Error logging is a core feature with dedicated support:
try {
// ... some code that might throw
} catch (error) {
logger.withError(error)
.withMetadata({ userId: "123" })
.error("Failed to process payment");
}
// Or log just the error
logger.errorOnly(error);
Flexible Configuration
LogLayer offers extensive configuration options:
- Custom error serialization
- Configurable field names for errors, context, and metadata
- Enable/disable logging at runtime
- Multiple transport support
- Plugin system for extending functionality
Clean Builder Pattern API
The builder pattern makes the API intuitive and chainable:
logger
.withContext({ env: "production" })
.withMetadata({ requestId: "abc-123" })
.withError(error)
.error("Operation failed");
Conclusion
LogLayer brings structure and consistency to your application's logging while remaining flexible and extensible. Its rich feature set and clean API make it an excellent choice for applications that need robust, structured logging capabilities.
What's Your Reaction?