• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PayU / prometheus-api-metrics / 5049301469

pending completion
5049301469

push

github

snyk-bot
fix: upgrade @types/koa from 2.13.4 to 2.13.6

108 of 151 branches covered (71.52%)

Branch coverage included in aggregate %.

187 of 237 relevant lines covered (78.9%)

18.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.04
/src/express-middleware.js
1
const Prometheus = require('prom-client');
1✔
2
require('pkginfo')(module, ['name']);
1✔
3
const debug = require('debug')(module.exports.name);
1✔
4
const utils = require('./utils');
1✔
5

6
class ExpressMiddleware {
7
    constructor(setupOptions) {
8
        this.setupOptions = setupOptions;
5✔
9
    }
10

11
    _collectDefaultServerMetrics(timeout) {
12
        const NUMBER_OF_CONNECTIONS_METRICS_NAME = 'expressjs_number_of_open_connections';
5✔
13
        this.setupOptions.numberOfConnectionsGauge = Prometheus.register.getSingleMetric(NUMBER_OF_CONNECTIONS_METRICS_NAME) || new Prometheus.Gauge({
5✔
14
            name: NUMBER_OF_CONNECTIONS_METRICS_NAME,
15
            help: 'Number of open connections to the Express.js server'
16
        });
17
        if (this.setupOptions.server) {
5!
18
            setInterval(this._getConnections.bind(this), timeout).unref();
5✔
19
        }
20
    }
21

22
    _getConnections() {
23
        if (this.setupOptions && this.setupOptions.server) {
×
24
            this.setupOptions.server.getConnections((error, count) => {
×
25
                if (error) {
×
26
                    debug('Error while collection number of open connections', error);
×
27
                } else {
28
                    this.setupOptions.numberOfConnectionsGauge.set(count);
×
29
                }
30
            });
31
        }
32
    }
33

34
    _handleResponse(req, res) {
35
        const responseLength = parseInt(res.get('Content-Length')) || 0;
53!
36

37
        const route = this._getRoute(req);
53✔
38

39
        if (route && utils.shouldLogMetrics(this.setupOptions.excludeRoutes, route)) {
53✔
40
            const labels = {
50✔
41
                method: req.method,
42
                route,
43
                code: res.statusCode,
44
                ...this.setupOptions.extractAdditionalLabelValuesFn(req, res)
45
            };
46
            this.setupOptions.requestSizeHistogram.observe(labels, req.metrics.contentLength);
50✔
47
            req.metrics.timer(labels);
50✔
48
            this.setupOptions.responseSizeHistogram.observe(labels, responseLength);
50✔
49
            debug(`metrics updated, request length: ${req.metrics.contentLength}, response length: ${responseLength}`);
50✔
50
        }
51
    }
52

53
    _getRoute(req) {
54
        let route = req.baseUrl;
53✔
55
        if (req.route) {
53✔
56
            if (req.route.path !== '/') {
48✔
57
                route = route ? route + req.route.path : req.route.path;
42✔
58
            }
59

60
            if (!route || route === '' || typeof route !== 'string') {
48✔
61
                route = req.originalUrl.split('?')[0];
5✔
62
            } else {
63
                const splittedRoute = route.split('/');
43✔
64
                const splittedUrl = req.originalUrl.split('?')[0].split('/');
43✔
65
                const routeIndex = splittedUrl.length - splittedRoute.length + 1;
43✔
66

67
                const baseUrl = splittedUrl.slice(0, routeIndex).join('/');
43✔
68
                route = baseUrl + route;
43✔
69
            }
70

71
            if (this.setupOptions.includeQueryParams === true && Object.keys(req.query).length > 0) {
48✔
72
                route = `${route}?${Object.keys(req.query).sort().map((queryParam) => `${queryParam}=<?>`).join('&')}`;
12✔
73
            }
74
        }
75

76
        // nest.js - build request url pattern if exists
77
        if (typeof req.params === 'object') {
53✔
78
            Object.keys(req.params).forEach((paramName) => {
52✔
79
                route = route.replace(req.params[paramName], ':' + paramName);
14✔
80
            });
81
        }
82

83
        // this condition will evaluate to true only in
84
        // express framework and no route was found for the request. if we log this metrics
85
        // we'll risk in a memory leak since the route is not a pattern but a hardcoded string.
86
        if (!route || route === '') {
53✔
87
            // if (!req.route && res && res.statusCode === 404) {
88
            route = 'N/A';
5✔
89
        }
90

91
        return route;
53✔
92
    }
93

94
    async middleware(req, res, next) {
95
        if (!this.setupOptions.server && req.socket) {
109✔
96
            this.setupOptions.server = req.socket.server;
5✔
97
            this._collectDefaultServerMetrics(this.setupOptions.defaultMetricsInterval);
5✔
98
        }
99

100
        const routeUrl = req.originalUrl || req.url;
109!
101

102
        if (routeUrl === this.setupOptions.metricsRoute) {
109✔
103
            debug('Request to /metrics endpoint');
55✔
104
            res.set('Content-Type', Prometheus.register.contentType);
55✔
105
            return res.end(await Prometheus.register.metrics());
55✔
106
        }
107
        if (routeUrl === `${this.setupOptions.metricsRoute}.json`) {
54✔
108
            debug('Request to /metrics endpoint');
1✔
109
            return res.json(await Prometheus.register.getMetricsAsJSON());
1✔
110
        }
111

112
        req.metrics = {
53✔
113
            timer: this.setupOptions.responseTimeHistogram.startTimer(),
114
            contentLength: parseInt(req.get('content-length')) || 0
102✔
115
        };
116

117
        debug(`Set start time and content length for request. url: ${routeUrl}, method: ${req.method}`);
53✔
118

119
        res.once('finish', () => {
53✔
120
            debug('on finish.');
53✔
121
            this._handleResponse(req, res);
53✔
122
        });
123

124
        return next();
53✔
125
    };
126
}
127

128
module.exports = ExpressMiddleware;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc