@fabbahiense/pulsar-node
v0.2.0
Published
Node.js SDK for Pulsar observability platform — auto-trace console.log, Express middleware, structured logger
Maintainers
Readme
@fabbahiense/pulsar-node
Node.js SDK for Pulsar — automatic trace context, console interception, and structured logging.
Install
npm install @fabbahiense/pulsar-nodeQuick Start
Mode 1 — Intercept console automatically
import { Pulsar } from '@fabbahiense/pulsar-node'
Pulsar.init({
url: 'https://your-pulsar-instance.com',
apiKey: 'psk_your_api_key',
interceptConsole: true,
})
console.log('This goes to Pulsar')
console.error('This too')Mode 2 — Structured logger
import { Pulsar } from '@fabbahiense/pulsar-node'
Pulsar.init({
url: 'https://your-pulsar-instance.com',
apiKey: 'psk_your_api_key',
})
const logger = Pulsar.createLogger({ serviceName: 'my-api' })
logger.info('Server started')
logger.error('Request failed', { traceId: '123' })Express Middleware (Automatic Trace ID)
The middleware uses AsyncLocalStorage to automatically attach a traceId to every log within a request lifecycle. Zero config needed.
import express from 'express'
import { Pulsar } from '@fabbahiense/pulsar-node'
Pulsar.init({
url: 'https://your-pulsar-instance.com',
apiKey: 'psk_your_api_key',
interceptConsole: true,
})
const app = express()
app.use(Pulsar.middleware())
app.get('/api/users', (req, res) => {
// traceId is automatically included in these logs
console.log('Fetching users')
console.log('Found 42 users')
res.json([])
})In Pulsar, clicking on any log shows all other logs from the same request — Magic Context.
The middleware:
- Reads
x-trace-idheader if present, otherwise generates a UUID - Stores
{ traceId, method, url }inAsyncLocalStorage - All
console.log/warn/errorandlogger.*calls within that request automatically include the traceId
Capturing request/response bodies, headers, query
Opt-in: each request gets a single log entry containing the full request/response cycle. Bodies are truncated to a max size and sensitive keys are redacted.
import express from 'express'
import { Pulsar } from '@fabbahiense/pulsar-node'
Pulsar.init({ url: '…', apiKey: 'psk_…' })
const app = express()
app.use(express.json()) // required so req.body is populated
app.use(Pulsar.middleware({
autoLog: true, // emit a log at end of each request
captureBody: true, // include req.body
captureResponseBody: true, // include res body (intercepts res.write/end)
captureHeaders: true, // include request/response headers (default true)
maxBodySize: 10240, // bytes; bigger bodies are truncated
redactKeys: ['cpf', 'creditCard'], // additional keys to redact
skipUrls: ['/health', '/favicon.ico'], // urls to skip
serviceName: 'api',
}))On Pulsar, the log opens with dedicated sections for Request body, Response body, Request/Response headers, Query and Path params, each with size and copy button.
Default redacted keys (always applied, case-insensitive):
password, token, secret, authorization, cookie, api-key, apikey, x-api-key.
Extra keys you list in redactKeys are also redacted (recursively in bodies and headers).
Manual capture (no middleware)
If you want full control:
const logger = Pulsar.createLogger({ serviceName: 'api' })
app.post('/checkout', async (req, res) => {
const result = await processCheckout(req.body)
logger.info('Checkout processed', {
requestBody: req.body, // recognized as request body
responseBody: result, // recognized as response body
statusCode: 200,
responseTime: 142,
})
res.json(result)
})Any of these key names are recognized automatically by Pulsar's UI:
body/requestBody/reqBody/payload/input, response/responseBody/output/result, headers/requestHeaders, responseHeaders, query/queryParams, params/pathParams.
Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| url | string | — | Pulsar server URL (required) |
| apiKey | string | — | API key (required) |
| serviceName | string | 'default' | Service name in Pulsar |
| interceptConsole | boolean | false | Monkey-patch console.log/warn/error |
| batchSize | number | 50 | Logs buffered before flush |
| flushInterval | number | 2000 | Flush interval in ms |
Shutdown
// Flush remaining logs before exiting
await Pulsar.shutdown()Features
- Automatic trace ID via
AsyncLocalStorage+ Express middleware - Auto-log requests with body/headers/query/params and response body/headers (opt-in)
- Smart redaction of sensitive keys (passwords, tokens, auth headers etc.)
- Body size limits with truncation instead of dropping
- Console interception (original output preserved)
- Structured logger with levels (trace, debug, info, warn, error, fatal)
- Batched delivery with retry and exponential backoff
- In-memory queue — no logs lost on temporary failures
- Zero runtime dependencies
- TypeScript types included
- Dual CJS/ESM package
License
MIT
