logctx
Version:
A Pino-based logger with context-aware logging using async_hooks
218 lines (155 loc) โข 5.29 kB
Markdown
# ๐ฆ logctx
> A lightweight, context-aware logger built on top of [Pino](https://github.com/pinojs/pino), using `async_hooks` and supporting decorators, DI, and easy context propagation across HTTP or Kafka requests.
## ๐ Features
- โ
Automatically injects context like `userId`, `traceId`, etc., into logs
- โ
Built with `async_hooks` for request-safe storage
- โ
Compatible with any Node.js framework (Express, Kafka, etc.)
- โ
Optional class decorator `@WithLogger()` for automatic logger injection
- โ
Customizable context shape with zero config by default
- โ
Built-in support for Pino transports like `pino-pretty`
- โ
Supports JSON or human-readable log formats via env
- โ
Optional log-to-file support with file rotation capability
- โ
Supports a generic logging middleware compatible with any framework
## ๐ฆ Installation
```bash
npm install logctx
````
Or with Yarn:
```bash
yarn add logctx
```
## ๐ ๏ธ Basic Usage
### 1. Import and use logger
```ts
import { runWithContext, ContextualLogger } from 'logctx';
const logger = new ContextualLogger();
runWithContext({ userId: '123', traceId: 'xyz' }, () => {
logger.log.info('This will include userId and traceId');
});
```
### 2. Use `@WithLogger()` Decorator
```ts
import { WithLogger } from 'logctx';
@WithLogger()
class UserService {
private log: any;
doWork() {
this.log.info('Logged with contextual metadata');
}
}
```
> โ ๏ธ Make sure you use a DI container (like `typedi`) or `Container.get(UserService)` so decorators are respected.
### 3. Configure Custom Context Getter (Optional)
By default, the logger uses whatever was passed via `runWithContext`.
But you can override this globally:
```ts
import { configureLoggerContext } from 'logctx';
configureLoggerContext(() => ({
userId: 'fallback-user',
tenantId: 'default-tenant'
}));
```
## โ๏ธ Environment Variables
| Variable | Description | Default |
| --------------- | ------------------------------------------------ | ---------------- |
| `APP_NAME` | Name to appear in logs | `logctx` |
| `LOG_LEVEL` | Logging level (`debug`, `info`, `warn`, `error`) | `info` |
| `LOG_FORMAT` | Log output format: `json` or `pretty` | `json` |
| `LOG_TO_FILE` | Enable file logging: `true` or `false` | `false` |
| `LOG_FILE_PATH` | File path to store logs (if `LOG_TO_FILE=true`) | `./logs/app.log` |
## ๐ง API Reference
### `runWithContext(context, callback)`
Wraps a function with the provided context for async propagation.
```ts
runWithContext({ userId: 'abc' }, () => {
logger.log.info('userId will be injected');
});
```
### `configureLoggerContext(getterFn)`
Globally defines a fallback context getter if none is set.
```ts
configureLoggerContext(() => ({ tenant: 'main', traceId: 'auto' }));
```
### `ContextualLogger`
Provides a `.log` object with `info`, `error`, `warn`, and `debug`.
```ts
const logger = new ContextualLogger();
logger.log.info('message');
```
### `@WithLogger()`
Injects `this.log` into any class. Works well with service or controller patterns.
```ts
@WithLogger()
class MyService {
private log: LoggerType; // optional for type hint
doSomething() {
this.log.info('Message with context');
}
}
```
### With middleware
Here's how you can integrate logctx into an Express application to enable contextual logging based on headers, query parameters, cookies, and route parameters.
```ts
import { createContextLogger, ContextualLogger } from "logctx";
import express from "express";
const logger = new ContextualLogger();
// Middleware to initialize context logger
function middleware(
req: express.Request,
res: express.Response,
next: express.NextFunction
) {
createContextLogger(req, next, {
headers: ['x-request-id', 'user-agent'],
queries: ['queryParam'],
cookies: ['sessionId'],
params: ['param1', 'param2'],
});
next(); // Important: call next middleware after context setup
}
const app = express();
app.use(middleware);
// Sample route using contextual logger
app.get('/', (req, res) => {
logger.log.info('Request received');
res.send('Hello from Express with Contextual Logger!');
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
```
## ๐ก Use Cases
* Log `userId`, `tenantId`, `traceId` across microservices
* Contextual logging for HTTP, WebSocket, Kafka
* Decorator-based logging without boilerplate
* Enforce consistent metadata across logs
* Switch easily between JSON and pretty logs using environment
* Persist logs to disk for production systems
* Use middleware with any NodeJS frameworks.
## ๐งช Example
```ts
import { runWithContext, ContextualLogger } from 'logctx';
const logger = new ContextualLogger();
runWithContext({ userId: 'U001' }, () => {
logger.log.info('User event started'); // includes userId automatically
});
```
## ๐จโ๐ป Contributing
Pull requests, issues, and suggestions welcome!
```bash
git clone https://github.com/AjayKrP/logctx.git
npm install
npm run build
```