Logging
Send structured logs through the Trasys OpenTelemetry pipeline, automatically enriched with the active trace ID, span ID, user ID, tenant ID, and request ID.
Logging
The Trasys logger sends structured log records through the OpenTelemetry pipeline. Every log entry is automatically enriched with the active trace ID, span ID, user ID, tenant ID, and request ID — so you can navigate from a trace in the dashboard directly to the logs from that request.
Basic usage
const { logger } = require('./trasys');
logger.debug('Cache miss', { key: 'user:123' });
logger.info('User signed in', { userId: user.id, method: 'oauth' });
logger.warn('Rate limit approaching', { remaining: 5, limit: 100 });
logger.error('Payment failed', { orderId, error: err });
logger.fatal('Database unreachable', { host: DB_HOST });All five methods share the same signature:
logger.info(message: string, context?: Record<string, unknown>): voidThe context object accepts any serializable key-value pairs, including nested objects.
Automatic enrichment
You do not need to add trace or user context to your log calls. The SDK reads them from the active request context and attaches them automatically:
| Field | Source |
|---|---|
trace.id | Active OpenTelemetry span |
span.id | Active OpenTelemetry span |
trasys.request.id | Set by HTTP middleware per request |
trasys.user.id | Read from req.user per your userIdPath config |
trasys.tenant.id | Read from req.user per your tenantIdPath config |
A log written inside a route handler automatically has the request ID, trace ID, and user ID attached — without passing them explicitly.
Logging errors
Pass the error as context.error. The SDK extracts error.type, error.message, and error.stack into structured fields:
try {
await processPayment(order);
} catch (err) {
logger.error('Payment processing failed', {
orderId: order.id,
amount: order.amount,
error: err, // Error instance — extracted automatically
});
}In non-production environments, the full stack trace is included. In production, only error.type and error.message are captured to avoid leaking internal paths.
Request logging pattern
Log inbound requests and responses in middleware that runs after sdk.middleware(). Because the Trasys middleware sets up the trace context, logs written in subsequent middleware are automatically correlated.
app.use(sdk.middleware()); // Trasys first — sets up trace context
app.use((req, res, next) => {
logger.info('Request received', {
method: req.method,
path: req.path,
ip: req.ip,
});
res.on('finish', () => {
const level = res.statusCode >= 500 ? 'error'
: res.statusCode >= 400 ? 'warn'
: 'info';
logger[level]('Response sent', {
method: req.method,
path: req.path,
statusCode: res.statusCode,
});
});
next();
});Severity levels
| Method | OTel SeverityNumber | When to use |
|---|---|---|
debug | DEBUG | Internal state, verbose diagnostics. Disable in production. |
info | INFO | Normal operation — user actions, service events. |
warn | WARN | Degraded but recoverable — rate limits, retries. |
error | ERROR | A request or operation failed. |
fatal | FATAL | Unrecoverable — service is about to crash. |
Winston integration
If your application already uses Winston, add TrasysWinstonTransport to forward Winston logs into the Trasys pipeline:
const winston = require('winston');
const { TrasysWinstonTransport } = require('@trasys/sdk');
const winstonLogger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console(),
new TrasysWinstonTransport({ level: 'debug' }), // forward to Trasys
],
});Winston level mapping:
| Winston level | OTel severity |
|---|---|
silly, verbose, debug | DEBUG |
http, info | INFO |
warn | WARN |
error | ERROR |
fatal, crit | FATAL |
The same automatic enrichment (trace ID, user ID, request ID) applies to forwarded Winston logs.
Next steps
- Custom Metrics — the
monitorobject also returned bycreateSdk, for counters, gauges, and histograms correlated with the active trace - TQL — query logs by severity, message, user, and trace
- Distributed Tracing — see logs in the context of full request traces
Sampling
Control which requests get recorded to manage data volume and cost — set per-route rates, and AI calls and debug users are always kept regardless of rate.
Distributed Tracing
Propagate W3C TraceContext across HTTP, gRPC, and message queues so a request spanning multiple services appears as one unified trace in the Trasys dashboard.

