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.
89 lines (88 loc) • 3.99 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.traceAxios = void 0;
const axios_1 = require("axios");
const types_1 = require("./types");
const storage_1 = require("./storage");
const utils_1 = require("./utils");
const span_1 = require("./span");
const buildUrl = (baseUrl, url) => {
return url?.startsWith('http') ? url : [baseUrl, url].filter(Boolean).join('');
};
const extractQueryParams = (url, config) => {
const object = new URL(url);
const query = { ...Object.fromEntries(object.searchParams.entries()), ...config.params };
const keys = Object.keys(query);
keys.forEach((key) => object.searchParams.delete(key));
return { url: object.toString(), query: keys.length > 0 ? query : undefined };
};
const buildOutgoingHttpPayload = (config, res) => ({
type: 'http',
http: {
...extractQueryParams(buildUrl(config.baseURL, config.url), config),
method: config.method?.toLowerCase() ?? 'get',
incoming: false,
request: {
headers: config.headers,
body: (0, utils_1.safeJsonParse)(config.data),
},
response: res
? {
headers: res?.headers,
status: res.status,
body: (0, utils_1.safeJsonParse)(res.data),
}
: undefined,
},
});
const getNoopPayload = () => ({});
/**
* Wraps an axios instance to add tracing and span tracking
* @param axios - The axios instance to wrap
* @param options - Configuration options for HTTP tracing
* @returns The wrapped axios instance with span tracking
*/
const traceAxios = (client, { ignoreTraceRoutes = types_1.defaultIgnoreTraceRoutes, traceHeaderKey = types_1.defaultTraceHeaderKey, getPayload = getNoopPayload, } = {
ignoreTraceRoutes: types_1.defaultIgnoreTraceRoutes,
traceHeaderKey: types_1.defaultTraceHeaderKey,
getPayload: getNoopPayload,
}) => {
const createSpanWrappedRequest = (originalMethod, method) => {
const { headers: defaultHeaders, ...partialDefaultConfig } = client.defaults;
const headers = { ...defaultHeaders.common, ...(method && defaultHeaders[method]) };
const defaultConfig = { ...partialDefaultConfig, headers };
return async (config) => {
config = (0, axios_1.mergeConfig)(defaultConfig, config);
const url = buildUrl(config.baseURL, config.url);
// Check if this request should be ignored
if ((0, utils_1.shouldIgnorePath)(url, ignoreTraceRoutes))
return originalMethod(config);
const traceId = storage_1.storage.getStore()?.traceId;
config = { ...config, headers: { ...config.headers, [traceHeaderKey]: traceId } };
// Execute the request within a span
return (0, span_1.startSpan)(`Outgoing HTTP request`, () => originalMethod(config), (options) => {
const response = options
? options.error
? (0, axios_1.isAxiosError)(options.error)
? options.error.response
: undefined
: options.result
: undefined;
return { ...buildOutgoingHttpPayload(config, response), ...getPayload(config, response) };
});
};
};
const request = client.request.bind(client);
const tracedRequest = createSpanWrappedRequest(request);
client.request = tracedRequest;
['post', 'put', 'patch'].forEach((method) => {
const func = createSpanWrappedRequest(request, method);
client[method] = (url, data, config) => func({ ...config, method, url, data });
});
['delete', 'get', 'head', 'options'].forEach((method) => {
const func = createSpanWrappedRequest(request, method);
client[method] = (url, config) => func({ ...config, method, url });
});
return client;
};
exports.traceAxios = traceAxios;