Message Logging Middleware
Logs request and response envelopes to a separate service group for monitoring and debugging. Designed as a companion to the Strata Queue Monitor (SQM), but works with any service that accepts the logged payload format.
Installation
npm install @strata-js/middleware-message-loggingPeer dependency: @strata-js/strata ^2.0.0
Usage
Create a MessageLoggingMiddleware instance with a StrataClient and configuration, then register it -- typically as global middleware so all requests are logged.
import { StrataService, StrataClient } from '@strata-js/strata';
import { MessageLoggingMiddleware } from '@strata-js/middleware-message-logging';
const service = new StrataService(serviceConfig);
const client = new StrataClient(clientConfig);
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: {
toMonitor: 'UserService',
toLogTo: 'StrataQueueMonitor',
},
});
service.useMiddleware(logging);
await client.start();
await service.start();The middleware uses the provided StrataClient to fire-and-forget (post) each logged envelope to the target service group. Logging is non-blocking -- it does not wait for the monitoring service to acknowledge receipt.
Configuration
MessageLoggingConfig
interface MessageLoggingConfig
{
serviceGroup : {
toMonitor : string;
toLogTo : string;
};
endpoint ?: {
context ?: string;
operation ?: string;
};
exclusions ?: string[];
logOnFailure ?: string[];
shouldLogRequestFn ?: (request : Request) => boolean;
transformRequestFn ?: (request : RequestEnvelope) => void;
transformResponseFn ?: (response : ResponseEnvelope) => void;
}| Option | Type | Default | Description |
|---|---|---|---|
serviceGroup.toMonitor | string | -- | The service group being monitored (used as the queue field in the logged payload). |
serviceGroup.toLogTo | string | -- | The service group to send logged messages to (e.g., 'StrataQueueMonitor'). |
endpoint.context | string | 'monitor' | The context on the logging service to post to. |
endpoint.operation | string | 'logMessage' | The operation on the logging service to post to. |
exclusions | string[] | [] | Endpoints to skip entirely (no request or response logging). |
logOnFailure | string[] | [] | Endpoints that are only logged when the request fails. |
shouldLogRequestFn | (request) => boolean | -- | Custom filter function. Return false to skip logging for a request. |
transformRequestFn | (envelope) => void | -- | Mutate the request envelope before it is logged (operates on a deep clone). |
transformResponseFn | (envelope) => void | -- | Mutate the response envelope before it is logged (operates on a deep clone). |
Exclusions
Skip logging for specific endpoints by listing them in exclusions. Each entry is a string in one of two forms:
'context.operation'-- exclude a specific operation'context.*'-- exclude an entire context
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: { toMonitor: 'UserService', toLogTo: 'StrataQueueMonitor' },
exclusions: [
'health.*', // Skip all health-check operations
'internal.refreshCache', // Skip a specific noisy operation
],
});Excluded endpoints are completely skipped -- neither request nor response envelopes are logged, even on failure.
Log on Failure
The logOnFailure list uses the same format as exclusions, but instead of silencing logging it defers it: the request envelope is only logged when the operation fails. The response envelope is always logged on failure.
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: { toMonitor: 'UserService', toLogTo: 'StrataQueueMonitor' },
logOnFailure: [
'batch.*', // Only log batch operations when they fail
'reports.generate', // Only log report generation on failure
],
});This is useful for high-volume endpoints where you only care about failures.
Custom Filtering
For filtering logic beyond simple string matching, provide a shouldLogRequestFn. It receives the full Request object and returns a boolean:
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: { toMonitor: 'UserService', toLogTo: 'StrataQueueMonitor' },
shouldLogRequestFn: (request) =>
{
// Only log requests from external clients
return !request.metadata?.internal;
},
});INFO
shouldLogRequestFn is checked in addition to exclusions and logOnFailure. If an endpoint is in exclusions, it is always skipped regardless of shouldLogRequestFn.
Transform Functions
The transformRequestFn and transformResponseFn options let you modify envelopes before they are logged. The middleware deep-clones the envelope first, so your mutations won't affect the actual request or response flowing through the service.
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: { toMonitor: 'UserService', toLogTo: 'StrataQueueMonitor' },
transformRequestFn: (envelope) =>
{
// Redact sensitive fields before logging
if(envelope.payload?.password)
{
envelope.payload.password = '[REDACTED]';
}
},
transformResponseFn: (envelope) =>
{
// Strip large payloads from logged responses
if(envelope.payload && JSON.stringify(envelope.payload).length > 10000)
{
envelope.payload = { _truncated: true };
}
},
});Logged Payload Format
Each logged message is posted with the following payload structure:
interface LoggedPayload
{
queue : string;
envelope : RequestEnvelope | ResponseEnvelope;
}queue-- For request envelopes, this isserviceGroup.toMonitor. For response envelopes, this is the request'sresponseQueue.envelope-- The full serialized request or response envelope.
Middleware Lifecycle
| Hook | Behavior |
|---|---|
beforeRequest | If the request passes all filters, posts the request envelope to the logging service. |
success | If the request passes all filters, posts the response envelope. |
failure | If not excluded, posts the response envelope. Also posts the request envelope if the endpoint is in logOnFailure. |
Examples
Global Logging with SQM
The most common setup -- log everything to the Strata Queue Monitor:
import { StrataService, StrataClient } from '@strata-js/strata';
import { MessageLoggingMiddleware } from '@strata-js/middleware-message-logging';
const service = new StrataService({
service: { serviceGroup: 'OrderService' },
backend: { type: 'redis-streams', redis: { host: 'localhost', port: 6379 } },
});
const client = new StrataClient({
backend: { type: 'redis-streams', redis: { host: 'localhost', port: 6379 } },
});
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: {
toMonitor: 'OrderService',
toLogTo: 'StrataQueueMonitor',
},
});
service.useMiddleware(logging);
await client.start();
await service.start();Custom Logging Endpoint
Route logs to a custom monitoring service:
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: {
toMonitor: 'OrderService',
toLogTo: 'CustomMonitor',
},
endpoint: {
context: 'audit',
operation: 'recordMessage',
},
});Selective Logging with Exclusions
Log everything except health checks and an internal cache refresh operation:
const logging = new MessageLoggingMiddleware(client, {
serviceGroup: {
toMonitor: 'OrderService',
toLogTo: 'StrataQueueMonitor',
},
exclusions: [
'service.*',
'internal.refreshCache',
],
logOnFailure: [
'batch.*',
],
});