@multiplayer-app/otlp-core
Version:
Multiplayer otlp core
140 lines • 7.09 kB
JavaScript
import * as zlib from 'zlib';
import { ATTR_MULTIPLAYER_HTTP_REQUEST_BODY, ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS, ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY, ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS, MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE, ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY_ENCODING, MULTIPLAYER_TRACE_DEBUG_PREFIX, } from './constants.node';
import { mask, schemify, isGzip, maskHeaders } from './helpers';
export const MultiplayerHttpInstrumentationHooksNode = {
responseHook: (options = {}) => (span, response) => {
try {
options = Object.assign({ maskDebSpanPayload: true, schemifyDocSpanPayload: true }, options);
const _response = response;
const traceId = span.spanContext().traceId;
if (_response.setHeader) {
_response.setHeader('X-Trace-Id', traceId);
}
const [oldWrite, oldEnd] = [_response.write, _response.end];
const chunks = [];
_response.write = function (...restArgs) {
chunks.push(Buffer.from(restArgs[0]));
// eslint-disable-next-line
// @ts-ignore
oldWrite.apply(_response, restArgs);
};
// eslint-disable-next-line
// @ts-ignore
_response.end = async function (...restArgs) {
if (restArgs[0]) {
chunks.push(Buffer.from(restArgs[0]));
}
const responseBuffer = Buffer.concat(chunks);
if (responseBuffer.byteLength === 0
|| responseBuffer.byteLength > (options.maxPayloadSize || MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE)) {
// eslint-disable-next-line
// @ts-ignore
return oldEnd.apply(_response, restArgs);
}
let responseBody;
let skipResponseBodyModification = false;
if (isGzip(responseBuffer)) {
if (options.uncompressPayload) {
const dezippedBuffer = await new Promise((resolve) => zlib
.gunzip(responseBuffer, function (err, dezipped) {
if (err) {
return resolve(Buffer.from(''));
}
else {
return resolve(dezipped);
}
}));
responseBody = dezippedBuffer.toString('utf-8');
}
else {
span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY_ENCODING, 'gzip');
skipResponseBodyModification = true;
responseBody = responseBuffer.toString('hex');
}
}
else {
responseBody = responseBuffer.toString('utf-8');
}
if (!skipResponseBodyModification) {
if (traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX)
&& options.maskDebSpanPayload) {
responseBody = mask(responseBody);
}
else if (options.schemifyDocSpanPayload) {
responseBody = schemify(responseBody);
}
else if (typeof responseBody !== 'string') {
responseBody = JSON.stringify(responseBody);
}
}
if (responseBody.length) {
span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY, responseBody);
}
const headers = maskHeaders(_response.getHeaders(), options.headersToMask);
const stringifiedHeaders = JSON.stringify(headers);
if (stringifiedHeaders === null || stringifiedHeaders === void 0 ? void 0 : stringifiedHeaders.length) {
span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS, stringifiedHeaders);
}
// eslint-disable-next-line
// @ts-ignore
return oldEnd.apply(_response, restArgs);
};
}
catch (error) {
// eslint-disable-next-line
console.error('An error occured in multiplayer otlp http responseHook', error);
}
},
requestHook: (options = {}) => (span, request) => {
var _a;
try {
options = Object.assign({ maskDebSpanPayload: true, schemifyDocSpanPayload: true }, options);
const traceId = span.spanContext().traceId;
const _request = request;
const contentType = (_a = _request === null || _request === void 0 ? void 0 : _request.headers) === null || _a === void 0 ? void 0 : _a['content-type'];
if (!contentType || !(contentType === null || contentType === void 0 ? void 0 : contentType.includes('application/json'))) {
return;
}
const headers = maskHeaders(_request.headers, options.headersToMask);
span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS, JSON.stringify(headers));
let body = '';
_request.on('data', (chunk) => {
body += chunk;
});
_request.on('end', () => {
try {
const requestBodySizeBytes = Buffer.byteLength(body, 'utf8');
if (requestBodySizeBytes === 0
|| requestBodySizeBytes > (options.maxPayloadSize || MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE)) {
return;
}
let requestBody = body;
if (!requestBody)
return;
if (traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX)
&& options.maskDebSpanPayload) {
requestBody = mask(requestBody);
}
else if (options.schemifyDocSpanPayload) {
requestBody = schemify(requestBody);
}
else if (typeof requestBody !== 'string') {
requestBody = JSON.stringify(requestBody);
}
if (requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) {
span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_BODY, requestBody);
}
}
catch (err) {
// eslint-disable-next-line
console.error('[MULTIPLAYER-HTTP-REQ-HOOK] An error occured in multiplayer otlp http requestHook', err);
}
});
}
catch (error) {
// eslint-disable-next-line
console.error('An error occured in multiplayer otlp http requestHook', error);
}
},
};
//# sourceMappingURL=MultiplayerHttpInstrumentationHooksNode.js.map