@stacksleuth/backend-agent
Version:
Comprehensive backend performance monitoring agent for Node.js applications - HTTP request tracing, database query optimization, memory profiling, and real-time metrics collection with WebSocket integration.
139 lines • 5.22 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BackendAgent = void 0;
exports.createBackendAgent = createBackendAgent;
const core_1 = require("@stacksleuth/core");
class BackendAgent {
constructor(config) {
this.collector = new core_1.TraceCollector(config);
}
/**
* Instrument an Express application
*/
instrument(app) {
// Middleware to trace all HTTP requests
app.use((req, res, next) => {
const trace = this.collector.startTrace(`${req.method} ${req.path}`, {
method: req.method,
url: req.url,
userAgent: req.get('User-Agent'),
ip: req.ip
});
if (!trace) {
return next();
}
const span = this.collector.startSpan(trace.id, `HTTP ${req.method} ${req.path}`, core_1.SpanType.HTTP_REQUEST, undefined, {
method: req.method,
url: req.url,
statusCode: res.statusCode,
userAgent: req.get('User-Agent')
});
// Store trace context in request
req.stacksleuthTrace = trace;
req.stacksleuthSpan = span;
// Hook into response to complete the trace
const originalSend = res.send;
res.send = function (body) {
if (span) {
const status = res.statusCode >= 400 ? core_1.TraceStatus.ERROR : core_1.TraceStatus.SUCCESS;
self.collector.completeSpan(span.id, status, {
statusCode: res.statusCode,
contentLength: Buffer.byteLength(body || '')
});
}
self.collector.completeTrace(trace.id, res.statusCode >= 400 ? core_1.TraceStatus.ERROR : core_1.TraceStatus.SUCCESS);
return originalSend.call(this, body);
};
const self = this;
next();
});
}
/**
* Manually trace a function or operation
*/
async trace(name, operation) {
// Get current trace from context if available
const activeTrace = this.collector.getAllTraces().find(t => t.status === core_1.TraceStatus.PENDING);
if (!activeTrace) {
// Create a new trace if none exists
const trace = this.collector.startTrace(name);
if (!trace)
return operation();
const span = this.collector.startSpan(trace.id, name, core_1.SpanType.FUNCTION_CALL);
try {
const result = await operation();
if (span)
this.collector.completeSpan(span.id, core_1.TraceStatus.SUCCESS);
this.collector.completeTrace(trace.id, core_1.TraceStatus.SUCCESS);
return result;
}
catch (error) {
if (span) {
this.collector.addSpanError(span.id, error);
this.collector.completeSpan(span.id, core_1.TraceStatus.ERROR);
}
this.collector.completeTrace(trace.id, core_1.TraceStatus.ERROR);
throw error;
}
}
else {
// Add span to existing trace
const span = this.collector.startSpan(activeTrace.id, name, core_1.SpanType.FUNCTION_CALL);
try {
const result = await operation();
if (span)
this.collector.completeSpan(span.id, core_1.TraceStatus.SUCCESS);
return result;
}
catch (error) {
if (span) {
this.collector.addSpanError(span.id, error);
this.collector.completeSpan(span.id, core_1.TraceStatus.ERROR);
}
throw error;
}
}
}
/**
* Create a traced handler wrapper for route handlers
*/
traceHandler(handler) {
return async (...args) => {
const req = args[0];
const trace = req.stacksleuthTrace;
if (!trace) {
return handler(...args);
}
const span = this.collector.startSpan(trace.id, `Handler ${req.method} ${req.path}`, core_1.SpanType.FUNCTION_CALL);
try {
const result = await handler(...args);
if (span)
this.collector.completeSpan(span.id, core_1.TraceStatus.SUCCESS);
return result;
}
catch (error) {
if (span) {
this.collector.addSpanError(span.id, error);
this.collector.completeSpan(span.id, core_1.TraceStatus.ERROR);
}
throw error;
}
};
}
/**
* Get the trace collector instance
*/
getCollector() {
return this.collector;
}
}
exports.BackendAgent = BackendAgent;
/**
* Factory function to create a backend agent
*/
function createBackendAgent(config) {
return new BackendAgent(config);
}
// Default export
exports.default = BackendAgent;
//# sourceMappingURL=index.js.map