UNPKG

nestjs-otel

Version:
132 lines (131 loc) 5.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApiMetricsMiddleware = void 0; const tslib_1 = require("tslib"); const common_1 = require("@nestjs/common"); const response_time_1 = tslib_1.__importDefault(require("response-time")); const urlParser = tslib_1.__importStar(require("url")); const metric_service_1 = require("../metrics/metric.service"); const opentelemetry_constants_1 = require("../opentelemetry.constants"); let ApiMetricsMiddleware = class ApiMetricsMiddleware { constructor(metricService, options = {}) { this.metricService = metricService; this.options = options; const { defaultAttributes = {}, ignoreUndefinedRoutes = false, prefix, } = options?.metrics?.apiMetrics ?? {}; this.defaultAttributes = defaultAttributes; this.ignoreUndefinedRoutes = ignoreUndefinedRoutes; // Semantic Convention this.httpServerRequestCount = this.metricService.getCounter('http.server.request.count', { description: 'Total number of HTTP requests', unit: 'requests', prefix, }); this.httpServerResponseCount = this.metricService.getCounter('http.server.response.count', { description: 'Total number of HTTP responses', unit: 'responses', prefix, }); this.httpServerAbortCount = this.metricService.getCounter('http.server.abort.count', { description: 'Total number of data transfers aborted', unit: 'requests', prefix, }); this.httpServerDuration = this.metricService.getHistogram('http.server.duration', { description: 'The duration of the inbound HTTP request', unit: 'ms', prefix, }); this.httpServerRequestSize = this.metricService.getHistogram('http.server.request.size', { description: 'Size of incoming bytes', unit: 'By', prefix, }); this.httpServerResponseSize = this.metricService.getHistogram('http.server.response.size', { description: 'Size of outgoing bytes', unit: 'By', prefix, }); // Helpers this.httpServerResponseSuccessCount = this.metricService.getCounter('http.server.response.success.count', { description: 'Total number of all successful responses', unit: 'responses', prefix, }); this.httpServerResponseErrorCount = this.metricService.getCounter('http.server.response.error.count', { description: 'Total number of all response errors', prefix, }); this.httpClientRequestErrorCount = this.metricService.getCounter('http.client.request.error.count', { description: 'Total number of client error requests', prefix, }); } use(req, res, next) { (0, response_time_1.default)((req, res, time) => { const { route, url, method } = req; let path; if (route) { path = route.path; } else if (this.ignoreUndefinedRoutes) { return; } else { path = urlParser.parse(url).pathname; } this.httpServerRequestCount.add(1, { method, path }); const requestLength = parseInt(req.headers['content-length'], 10) || 0; const responseLength = parseInt(res.getHeader('Content-Length'), 10) || 0; const status = res.statusCode || 500; const attributes = { method, status, path, ...this.defaultAttributes, }; this.httpServerRequestSize.record(requestLength, attributes); this.httpServerResponseSize.record(responseLength, attributes); this.httpServerResponseCount.add(1, attributes); this.httpServerDuration.record(time, attributes); const codeClass = this.getStatusCodeClass(status); switch (codeClass) { case 'success': this.httpServerResponseSuccessCount.add(1); break; case 'redirect': // TODO: Review what should be appropriate for redirects. this.httpServerResponseSuccessCount.add(1); break; case 'client_error': this.httpClientRequestErrorCount.add(1); break; case 'server_error': this.httpServerResponseErrorCount.add(1); break; } req.on('end', () => { if (req.aborted === true) { this.httpServerAbortCount.add(1); } }); })(req, res, next); } getStatusCodeClass(code) { if (code < 200) return 'info'; if (code < 300) return 'success'; if (code < 400) return 'redirect'; if (code < 500) return 'client_error'; return 'server_error'; } }; exports.ApiMetricsMiddleware = ApiMetricsMiddleware; exports.ApiMetricsMiddleware = ApiMetricsMiddleware = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__param(0, (0, common_1.Inject)(metric_service_1.MetricService)), tslib_1.__param(1, (0, common_1.Inject)(opentelemetry_constants_1.OPENTELEMETRY_MODULE_OPTIONS)), tslib_1.__metadata("design:paramtypes", [metric_service_1.MetricService, Object]) ], ApiMetricsMiddleware);