unnbound-logger-sdk
Version:
A structured logging library with TypeScript support using Pino. Provides consistent, well-typed logging with automatic logId, workflowId, traceId, and deploymentId tracking across operational contexts.
86 lines (85 loc) • 3.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.traceMiddleware = void 0;
const span_1 = require("./span");
const types_1 = require("./types");
const utils_1 = require("./utils");
const trace_1 = require("./trace");
const extractQueryParams = (url) => {
const object = new URL(url);
const query = Object.fromEntries(object.searchParams.entries());
const keys = Object.keys(query);
keys.forEach((key) => object.searchParams.delete(key));
return { url: object.toString(), query: keys.length > 0 ? query : undefined };
};
const getFullUrl = (req) => {
const url = req.originalUrl || req.url;
if (url?.startsWith('http://') || url?.startsWith('https://'))
return url;
// Check if we have a workflow URL configured (preferred method)
if (process.env.UNNBOUND_WORKFLOW_URL) {
// Use workflow URL as the base URL
return `https://${process.env.UNNBOUND_WORKFLOW_URL.replace(/\/$/, '')}${url}`;
}
// Fallback to constructing from request info for incoming requests
const protocol = req.protocol || (req.secure ? 'https' : 'http');
const host = req.get('host') || req.get('x-forwarded-host') || 'localhost';
return `${protocol}://${host}${url}`;
};
const buildIncomingHttpPayload = (req, res) => ({
type: 'http',
http: {
...extractQueryParams(getFullUrl(req)),
method: req.method.toLowerCase(),
ip: (0, utils_1.normalizeIp)(req.ip),
incoming: true,
request: {
headers: req.headers,
body: (0, utils_1.safeJsonParse)(req.body),
},
response: res
? {
headers: res.headers,
status: res.status,
body: (0, utils_1.safeJsonParse)(res.body),
}
: undefined,
},
});
const getNoopPayload = () => ({});
const traceMiddleware = ({ ignoreTraceRoutes = types_1.defaultIgnoreTraceRoutes, traceHeaderKey = types_1.defaultTraceHeaderKey, messageHeaderKey = types_1.defaultMessageHeaderKey, getPayload = getNoopPayload, } = {
ignoreTraceRoutes: types_1.defaultIgnoreTraceRoutes,
traceHeaderKey: types_1.defaultTraceHeaderKey,
messageHeaderKey: types_1.defaultMessageHeaderKey,
getPayload: getNoopPayload,
}) => async (req, res, next) => {
if ((0, utils_1.shouldIgnorePath)(req.path, ignoreTraceRoutes))
return next();
const traceId = req.header(traceHeaderKey) || (0, trace_1.getTraceId)();
const messageId = req.header(messageHeaderKey) || undefined;
res.setHeader(traceHeaderKey, traceId);
return await (0, trace_1.withTrace)(async () => {
return await (0, span_1.startSpan)('Incoming HTTP request', async () => {
return new Promise((resolve) => {
// Capture response body for logging
const send = res.send.bind(res);
res.send = (body) => {
res.locals.body = body;
return send(body);
};
res.on('finish', () => resolve());
return next();
});
}, (o) => {
const response = o
? {
status: res.statusCode,
headers: res.getHeaders(),
body: res.locals.body,
}
: undefined;
return { ...buildIncomingHttpPayload(req, response), ...getPayload(req, response) };
});
}, messageId ? { traceId, messageId } : { traceId });
};
exports.traceMiddleware = traceMiddleware;