@superreach/sr-logger
v1.0.4
Published
Shared structured logging package for SuperReach backend services
Maintainers
Readme
@superreach/sr-logger
Shared structured logging package for SuperReach backend services (Control Plane, Data Plane / AI Services, Billing).
Architecture
createLogger(config) ← called once at service startup
│
├── AsyncLocalStorage context ← requestMiddleware auto-populates
├── Classification engine ← severity / risk_level / requires_review
├── Console transport ← JSON or pretty-print
├── Logstash transport ← TCP, optional, config-driven
└── Sink registry ← registerSink("name", async fn)This package owns zero databases and zero credentials. All config comes from the consuming service.
Installation
npm install @superreach/sr-logger
# Peer dep (required only if using requestMiddleware):
npm install koaQuick Start
import { createLogger, requestMiddleware, registerSink } from '@superreach/sr-logger'
const logger = createLogger({
service: process.env.SR_SERVICE!,
appId: process.env.SR_APP_ID!,
env: process.env.SR_ENV!,
region: process.env.SR_REGION!,
logLevel: process.env.SR_LOG_LEVEL ?? 'info',
console: {
enabled: process.env.SR_ENABLE_CONSOLE === 'true',
},
logstash: {
enabled: process.env.SR_ENABLE_LOGSTASH === 'true',
host: process.env.LOGSTASH_HOST,
port: Number(process.env.LOGSTASH_PORT),
username: process.env.LOGSTASH_USER,
password: process.env.LOGSTASH_PASSWORD,
},
})Environment Variables
| Variable | Required | Description |
|---|---|---|
| SR_SERVICE | ✅ | Service name, e.g. control-plane |
| SR_APP_ID | ✅ | App identifier |
| SR_ENV | ✅ | production / staging / development |
| SR_REGION | ✅ | e.g. us-east-1 |
| SR_LOG_LEVEL | ❌ | debug / info / warn / error / fatal (default info) |
| SR_ENABLE_CONSOLE | ❌ | true to enable console output |
| SR_ENABLE_LOGSTASH | ❌ | true to enable Logstash TCP transport |
| LOGSTASH_HOST | ❌* | Required when Logstash enabled |
| LOGSTASH_PORT | ❌* | Required when Logstash enabled |
| LOGSTASH_USER | ❌ | Basic auth username |
| LOGSTASH_PASSWORD | ❌ | Basic auth password |
API Reference
createLogger(config): Logger
Initializes the global logger. Call once at app startup.
getLogger(): Logger
Retrieve the initialized logger from anywhere without re-passing config.
createModuleLogger(moduleName): ModuleLogger
Scoped logger that appends meta.module to every event.
const paymentLogger = logger.createModuleLogger('payments')
await paymentLogger.emitBillingEvent({ ... })runWithContext(context, callback)
Wraps a callback in an AsyncLocalStorage context. The requestMiddleware calls this automatically.
setContext(partial) / getContext()
Mutate or read the current ALS context from within a running request.
requestMiddleware(options): KoaMiddleware
Koa middleware that auto-populates request_id, trace_id, tenant_id, workspace_id, actor_id, actor_type, ip_address, user_agent from request headers.
app.use(requestMiddleware({
tenantIdHeader: 'x-tenant-id',
extractContext: (ctx) => ({ department_id: ctx.get('x-dept-id') }),
}))Event Emitters
| Method | Category |
|---|---|
| emitAuditEvent(payload) | audit |
| emitSecurityEvent(payload) | security |
| emitBillingEvent(payload) | billing |
| emitExecutionEvent(payload) | execution |
| emitDataEvent(payload) | data |
| emitSystemEvent(payload) | system |
| emitIntegrationEvent(payload) | integration |
All methods return Promise<void> and never throw — transport/sink errors are caught internally.
registerSink(name, fn: async (event) => void)
Register a custom sink. Called after validation + classification.
registerSink('mongo-audit', async (event) => {
await db.collection('audit_logs').insertOne(event)
})Event Schema
Every emitted event conforms to BaseEvent:
{
event_id, // UUIDv4
event_version, // "1.0"
timestamp, // ISO 8601
level, // mapped from severity
category, // audit | security | billing | execution | data | system | integration
event_class, // e.g. "iam", "auth", "subscription"
event_type, // e.g. "user_login", "sign_in_failed"
severity, // debug | info | notice | warning | error | critical | alert | emergency
risk_level, // none | low | medium | high | critical
requires_review,// boolean — auto-set by classifier
outcome, // success | failure | partial | pending | unknown
service, // from config
app_id, // from config
env, // from config
region, // from config
tenant_id, // from context or payload
workspace_id, // from context or payload
request_id, // from ALS context
trace_id, // from ALS context
actor_id, // from payload or context
actor_type, // user | service | system | agent | anonymous
action, // from payload
resource, // optional
resource_id, // optional
message, // from payload
tags, // optional string[]
meta, // optional freeform object
}Classification Rules
| Pattern | Risk Level |
|---|---|
| impersonat* | critical |
| privilege_escalat* | high |
| webhook_signature_fail* | critical |
| brute_force*, credential_stuff* | critical |
| account_takeover, data_exfiltration | critical |
| sign_in_failed (outcome=failure) | medium |
| Normal audit/API events | none / low |
High + critical events automatically set requires_review: true.
Build & Test
# Install deps
npm install
# Build to dist/
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Watch mode
npm run build:watch
npm run test:watchUsage in Services
// control-plane/src/app.ts
import { createLogger, requestMiddleware } from '@superreach/sr-logger'
const logger = createLogger({
service: process.env.SR_SERVICE!,
// ...
})
app.use(requestMiddleware())
// control-plane/src/routes/auth.ts — getLogger() works anywhere after init
import { getLogger } from '@superreach/sr-logger'
const logger = getLogger()
await logger.emitSecurityEvent({ ... })