@batkit/logger
v1.0.1
Published
Logger facade with default console implementation for Node.js and browser
Maintainers
Readme
@batkit/logger
Logger facade with default console implementation for Node.js and browser environments.
Installation
npm install @batkit/loggerOverview
A lightweight logger facade that provides a consistent logging interface for both Node.js and browser environments. Includes a production-ready console logger implementation with structured logging support.
Developing in this monorepo
This package builds two outputs (index / console and the Node-only @batkit/logger/async-local) using tsup (see tsup.config.ts and tsup.async-local.config.ts). The dev script runs concurrently so both tsup --watch processes start together. From the repo root, vp run dev starts the Express reference app and workspace watchers (including this package). From packages/logger, run vp run dev for logger-only watch mode.
Features
- ✅ Simple, intuitive API
- ✅ Works in Node.js and browsers (the main entry is isomorphic;
@batkit/logger/async-localis Node-only) - ✅ Structured logging support
- ✅ Async-local log context (Node):
@batkit/logger/async-local - ✅ Log level filtering
- ✅ Pretty and JSON output modes
- ✅ Zero runtime dependencies on the core facade
- ✅ TypeScript-first
- ✅ ESM and CommonJS support
Usage
Basic Logging
import { LoggerFacade } from "@batkit/logger";
const logger = LoggerFacade.getLogger("my-app");
logger.debug("Debug message");
logger.info("Application started");
logger.warn("Low disk space");
logger.error(new Error("Failed to connect to database"));Structured Logging
import { LoggerFacade } from "@batkit/logger";
const logger = LoggerFacade.getLogger("my-app");
// Add structured data to logs
logger.info("User logged in", {
userId: "123",
timestamp: Date.now(),
ipAddress: "192.168.1.1",
});
// Error logging (error first, then message, then context)
try {
// ... some code
} catch (error) {
if (error instanceof Error) {
logger.error(error, "Operation failed", { operation: "createUser" });
}
}Async-local log context (Node only)
Background: Understanding AsyncLocalStorage
For request- or job-scoped fields (requestId, transactionId, etc.), use the @batkit/logger/async-local entry (built on AsyncLocalStorage). Wrap your LoggerProvider with ContextualLoggerProvider once at bootstrap, then everywhere else call mergeContext/runWithContext on the Logger instance you already have from LoggerFacade.getLogger(...)—no further @batkit/logger/async-local import needed.
// bootstrap.ts — one-time setup
import { LoggerFacade } from "@batkit/logger";
import { ContextualLoggerProvider } from "@batkit/logger/async-local";
import { PinoLoggerProvider } from "@batkit/logger-pino";
LoggerFacade.setProvider(new ContextualLoggerProvider(new PinoLoggerProvider({ level: "info" })));// anywhere else — only ever imports LoggerFacade
import { LoggerFacade } from "@batkit/logger";
import { randomUUID } from "node:crypto";
const log = LoggerFacade.getLogger("payments");
log.runWithContext({ requestId: randomUUID() }, () => {
log.mergeContext({ transactionId: "txn-123" });
log.info("Captured"); // structured context includes both ids
});Need the raw context bag directly (rare—e.g. forwarding correlation ids to a non-logging call)? getLogContext from @batkit/logger/async-local reads it without a Logger instance.
In Express, mount logContextMiddleware early instead of calling runWithContext yourself at the top of every route.
JSON / structured output
For JSON log lines in production, use @batkit/logger-pino (or another LoggerProvider) and attach it with LoggerFacade.setProvider.
API Reference
See exported types in src/types.ts. Highlights:
Logger—debug/info/warn/erroruse theLogMethodoverloads (context-only, message + context, error + context, error + message + context). AlsomergeContext(partial)andrunWithContext(initial, fn)(real when wrapped withContextualLoggerProvider; the default console logger'smergeContextthrows with setup instructions).LoggerProvider—getLogger(name),isLogLevelEnabled.LoggerFacade—getLogger,setProvider,getProvider,configure.- Node-only:
@batkit/logger/async-local—ContextualLoggerProvider(bootstrap) plusgetLogContextfor reading the raw context bag without aLoggerinstance.
Using with Other Implementations
This package provides the logger facade. You can use alternative implementations:
- @batkit/logger-pino - Pino.js based implementation (recommended for production)
import type { Logger } from "@batkit/logger";
import { PinoLoggerProvider } from "@batkit/logger-pino";
// Example: use LoggerFacade.setProvider(new PinoLoggerProvider({ level: 'info' }))
// or wrap with ContextualLoggerProvider when using async-local context.
const provider = new PinoLoggerProvider({ level: "info" });
const logger: Logger = provider.getLogger("app");
logger.info("Using Pino implementation");Integration with Express
Use logContextMiddleware together with ContextualLoggerProvider so each request runs inside runWithContext and structured logs include correlation fields. See apps/express-api for a full example (POST /api/demo/fulfillment).
Best Practices
Use appropriate log levels:
debug: Detailed diagnostic informationinfo: General informational messageswarn: Warning messages for potentially harmful situationserror: Error messages for failures
Add structured context instead of string interpolation:
// ✅ Good logger.info("User created", { userId, email }); // ❌ Avoid logger.info(`User ${userId} created with email ${email}`);Use
@batkit/logger/async-localon Node when many layers need the same correlation ids without threading them through every functionInclude errors first (per
LogMethodoverloads), then optional message, then context:logger.error(error, "Failed to save user", { userId });
TypeScript
Full TypeScript support with exported types:
import type { Logger, LoggerProvider } from "@batkit/logger";
function setupLogger(provider: LoggerProvider, name: string): Logger {
return provider.getLogger(name);
}Tree-Shaking
For optimal tree-shaking, import from the specific entry point:
// Import only the console entry (re-exports console helpers)
import { ConsoleLoggerProvider } from "@batkit/logger/console";Node-only: @batkit/logger/async-local
Links
License
MIT © Ken Courville
