UNPKG

@stoplight/moleculer

Version:

Fast & powerful microservices framework for Node.JS

448 lines (415 loc) 12.3 kB
/* * moleculer * Copyright (c) 2020 MoleculerJS (https://github.com/moleculerjs/moleculer) * MIT Licensed */ "use strict"; const { METRIC } = require("../metrics"); module.exports = function MetricsMiddleware(broker) { const metrics = broker.metrics; function getActionHandler(type, actionDef, next) { const action = actionDef.name; const service = actionDef.service ? actionDef.service.fullName : null; return function metricsMiddleware(ctx) { const caller = ctx.caller; metrics.increment(METRIC.MOLECULER_REQUEST_TOTAL, { service, action, caller, type }); metrics.increment(METRIC.MOLECULER_REQUEST_ACTIVE, { service, action, caller, type }); metrics.increment(METRIC.MOLECULER_REQUEST_LEVELS, { service, action, caller, level: ctx.level }); const timeEnd = metrics.timer(METRIC.MOLECULER_REQUEST_TIME, { service, action, caller, type }); // Call the next handler return next(ctx) .then(res => { timeEnd(); metrics.decrement(METRIC.MOLECULER_REQUEST_ACTIVE, { service, action, caller, type }); return res; }) .catch(err => { timeEnd(); metrics.decrement(METRIC.MOLECULER_REQUEST_ACTIVE, { service, action, caller, type }); metrics.increment(METRIC.MOLECULER_REQUEST_ERROR_TOTAL, { service, action, caller, type, errorName: err ? err.name : null, errorCode: err ? err.code : null, errorType: err ? err.type : null }); throw err; }); }; } return { name: "Metrics", created() { if (broker.isMetricsEnabled()) { // --- MOLECULER REQUEST METRICS --- metrics.register({ name: METRIC.MOLECULER_REQUEST_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["service", "action", "type", "caller"], unit: METRIC.UNIT_REQUEST, description: "Number of requests", rate: true }); metrics.register({ name: METRIC.MOLECULER_REQUEST_ACTIVE, type: METRIC.TYPE_GAUGE, labelNames: ["service", "action", "type", "caller"], unit: METRIC.UNIT_REQUEST, description: "Number of active requests" }); metrics.register({ name: METRIC.MOLECULER_REQUEST_ERROR_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: [ "service", "action", "type", "caller", "errorName", "errorCode", "errorType" ], unit: METRIC.UNIT_REQUEST, description: "Number of request errors", rate: true }); metrics.register({ name: METRIC.MOLECULER_REQUEST_TIME, type: METRIC.TYPE_HISTOGRAM, labelNames: ["service", "action", "type", "caller"], quantiles: true, buckets: true, unit: METRIC.UNIT_MILLISECONDS, description: "Request times in milliseconds", rate: true }); metrics.register({ name: METRIC.MOLECULER_REQUEST_LEVELS, type: METRIC.TYPE_COUNTER, labelNames: ["level"], unit: METRIC.UNIT_REQUEST, description: "Number of requests by context level" }); //metrics.register({ name: METRIC.MOLECULER_REQUEST_DIRECTCALL_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["action"], unit: METRIC.UNIT_REQUEST, description: "Number of direct calls", rate: true }); //metrics.register({ name: METRIC.MOLECULER_REQUEST_MULTICALL_TOTAL, type: METRIC.TYPE_COUNTER, unit: METRIC.UNIT_REQUEST, description: "Number of multicalls", rate: true }); // --- MOLECULER EVENTS METRICS --- metrics.register({ name: METRIC.MOLECULER_EVENT_EMIT_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["event", "groups"], unit: METRIC.UNIT_EVENT, description: "Number of emitted events", rate: true }); metrics.register({ name: METRIC.MOLECULER_EVENT_BROADCAST_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["event", "groups"], unit: METRIC.UNIT_EVENT, description: "Number of broadcast events", rate: true }); metrics.register({ name: METRIC.MOLECULER_EVENT_BROADCASTLOCAL_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["event", "groups"], unit: METRIC.UNIT_EVENT, description: "Number of local broadcast events", rate: true }); metrics.register({ name: METRIC.MOLECULER_EVENT_RECEIVED_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["service", "group", "event", "caller"], unit: METRIC.UNIT_EVENT, description: "Number of received events", rate: true }); metrics.register({ name: METRIC.MOLECULER_EVENT_RECEIVED_ACTIVE, type: METRIC.TYPE_GAUGE, labelNames: ["service", "group", "event", "caller"], unit: METRIC.UNIT_REQUEST, description: "Number of active event executions" }); metrics.register({ name: METRIC.MOLECULER_EVENT_RECEIVED_ERROR_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: [ "service", "group", "event", "caller", "errorName", "errorCode", "errorType" ], unit: METRIC.UNIT_REQUEST, description: "Number of event execution errors", rate: true }); metrics.register({ name: METRIC.MOLECULER_EVENT_RECEIVED_TIME, type: METRIC.TYPE_HISTOGRAM, labelNames: ["service", "group", "event", "caller"], quantiles: true, buckets: true, unit: METRIC.UNIT_MILLISECONDS, description: "Execution time of events in milliseconds", rate: true }); // --- MOLECULER TRANSIT METRICS --- metrics.register({ name: METRIC.MOLECULER_TRANSIT_PUBLISH_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["type"], unit: METRIC.UNIT_PACKET, description: "Number of published packets", rate: true }); metrics.register({ name: METRIC.MOLECULER_TRANSIT_RECEIVE_TOTAL, type: METRIC.TYPE_COUNTER, labelNames: ["type"], unit: METRIC.UNIT_PACKET, description: "Number of received packets", rate: true }); metrics.register({ name: METRIC.MOLECULER_TRANSIT_REQUESTS_ACTIVE, type: METRIC.TYPE_GAUGE, unit: METRIC.UNIT_REQUEST, description: "Number of active requests" }); metrics.register({ name: METRIC.MOLECULER_TRANSIT_STREAMS_SEND_ACTIVE, type: METRIC.TYPE_GAUGE, unit: METRIC.UNIT_STREAM, description: "Number of active sent streams" }); //metrics.register({ name: METRIC.MOLECULER_TRANSIT_STREAMS_RECEIVE_ACTIVE, type: METRIC.TYPE_GAUGE, description: "" }); // --- MOLECULER TRANSPORTER METRICS --- metrics.register({ name: METRIC.MOLECULER_TRANSPORTER_PACKETS_SENT_TOTAL, type: METRIC.TYPE_COUNTER, unit: METRIC.UNIT_PACKET, description: "Number of sent packets", rate: true }); metrics.register({ name: METRIC.MOLECULER_TRANSPORTER_PACKETS_SENT_BYTES, type: METRIC.TYPE_COUNTER, unit: METRIC.UNIT_BYTE, description: "Number of sent bytes", rate: true }); metrics.register({ name: METRIC.MOLECULER_TRANSPORTER_PACKETS_RECEIVED_TOTAL, type: METRIC.TYPE_COUNTER, unit: METRIC.UNIT_PACKET, description: "Number of received packets", rate: true }); metrics.register({ name: METRIC.MOLECULER_TRANSPORTER_PACKETS_RECEIVED_BYTES, type: METRIC.TYPE_COUNTER, unit: METRIC.UNIT_BYTE, description: "Number of received bytes", rate: true }); } }, localAction(next, action) { if (broker.isMetricsEnabled()) return getActionHandler("local", action, next); return next; }, remoteAction(next, action) { if (broker.isMetricsEnabled()) return getActionHandler("remote", action, next); return next; }, // Wrap local event handlers localEvent(next, event) { const service = event.service ? event.service.name : null; if (broker.isMetricsEnabled()) { return function metricsMiddleware(ctx) { const group = event.group || service; metrics.increment(METRIC.MOLECULER_EVENT_RECEIVED_TOTAL, { service, event: ctx.eventName, group, caller: ctx.caller }); metrics.increment(METRIC.MOLECULER_EVENT_RECEIVED_ACTIVE, { service, event: ctx.eventName, group, caller: ctx.caller }); const timeEnd = metrics.timer(METRIC.MOLECULER_EVENT_RECEIVED_TIME, { service, event: ctx.eventName, group, caller: ctx.caller }); return next .apply(this, arguments) .then(res => { timeEnd(); metrics.decrement(METRIC.MOLECULER_EVENT_RECEIVED_ACTIVE, { service, event: ctx.eventName, group, caller: ctx.caller }); return res; }) .catch(err => { timeEnd(); metrics.decrement(METRIC.MOLECULER_EVENT_RECEIVED_ACTIVE, { service, event: ctx.eventName, group, caller: ctx.caller }); metrics.increment(METRIC.MOLECULER_EVENT_RECEIVED_ERROR_TOTAL, { service, event: ctx.eventName, group, caller: ctx.caller, errorName: err ? err.name : null, errorCode: err ? err.code : null, errorType: err ? err.type : null }); throw err; }); }.bind(this); } return next; }, // Wrap broker.emit method emit(next) { if (broker.isMetricsEnabled()) { return function metricsMiddleware(/* event, payload */) { metrics.increment(METRIC.MOLECULER_EVENT_EMIT_TOTAL, { event: arguments[0] }); return next.apply(this, arguments); }; } return next; }, // Wrap broker.broadcast method broadcast(next) { if (broker.isMetricsEnabled()) { return function metricsMiddleware(/* event, payload */) { metrics.increment(METRIC.MOLECULER_EVENT_BROADCAST_TOTAL, { event: arguments[0] }); return next.apply(this, arguments); }; } return next; }, // Wrap broker.broadcastLocal method broadcastLocal(next) { if (broker.isMetricsEnabled()) { return function metricsMiddleware(/* event, payload */) { metrics.increment(METRIC.MOLECULER_EVENT_BROADCASTLOCAL_TOTAL, { event: arguments[0] }); return next.apply(this, arguments); }; } return next; }, // When transit publishing a packet transitPublish(next) { const transit = this; if (broker.isMetricsEnabled()) { return function metricsMiddleware(/* packet */) { metrics.increment(METRIC.MOLECULER_TRANSIT_PUBLISH_TOTAL, { type: arguments[0].type }); const p = next.apply(this, arguments); metrics.increment( METRIC.MOLECULER_TRANSIT_REQUESTS_ACTIVE, null, transit.pendingRequests.size ); //metrics.increment(METRIC.MOLECULER_TRANSIT_STREAMS_RECEIVE_ACTIVE, null, transit.); metrics.increment( METRIC.MOLECULER_TRANSIT_STREAMS_SEND_ACTIVE, null, transit.pendingReqStreams.size + this.pendingResStreams.size ); return p; }; } return next; }, // When transit receives & handles a packet transitMessageHandler(next) { if (broker.isMetricsEnabled()) { return function metricsMiddleware(/* cmd, packet */) { metrics.increment(METRIC.MOLECULER_TRANSIT_RECEIVE_TOTAL, { type: arguments[0] }); return next.apply(this, arguments); }; } return next; }, // When transporter send data transporterSend(next) { if (broker.isMetricsEnabled()) { return function metricsMiddleware(/* topic, data, meta */) { const data = arguments[1]; metrics.increment(METRIC.MOLECULER_TRANSPORTER_PACKETS_SENT_TOTAL); metrics.increment( METRIC.MOLECULER_TRANSPORTER_PACKETS_SENT_BYTES, null, data && data.length ? data.length : 0 ); return next.apply(this, arguments); }; } return next; }, // When transporter received data transporterReceive(next) { if (broker.isMetricsEnabled()) { return function metricsMiddleware(/* cmd, data, s */) { const data = arguments[1]; metrics.increment(METRIC.MOLECULER_TRANSPORTER_PACKETS_RECEIVED_TOTAL); metrics.increment( METRIC.MOLECULER_TRANSPORTER_PACKETS_RECEIVED_BYTES, null, data && data.length ? data.length : 0 ); return next.apply(this, arguments); }; } return next; } }; };