monitoring.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /**
  2. * @description MeshCentral monitoring module
  3. * @author Simon Smith
  4. * @license Apache-2.0
  5. * @version v0.0.1
  6. */
  7. "use strict";
  8. module.exports.CreateMonitoring = function (parent, args) {
  9. var obj = {};
  10. obj.args = args;
  11. obj.parent = parent;
  12. obj.express = require('express');
  13. obj.app = obj.express();
  14. obj.prometheus = null;
  15. obj.app.disable('x-powered-by');
  16. obj.counterMetrics = { // Counter Metrics always start at 0 and increase but never decrease
  17. RelayErrors: { description: "Relay Errors" }, // parent.webserver.relaySessionErrorCount
  18. UnknownGroup: { description: "Unknown Group" }, // meshDoesNotExistCount
  19. InvalidPKCSsignature: { description: "Invalid PKCS signature" }, // invalidPkcsSignatureCount
  20. InvalidRSAsignature: { description: "Invalid RSA signature" }, // invalidRsaSignatureCount
  21. InvalidJSON: { description: "Invalid JSON" }, // invalidJsonCount
  22. UnknownAction: { description: "Unknown Action" }, // unknownAgentActionCount
  23. BadWebCertificate: { description: "Bad Web Certificate" }, // agentBadWebCertHashCount
  24. BadSignature: { description: "Bad Signature" }, // (agentBadSignature1Count + agentBadSignature2Count)
  25. MaxSessionsReached: { description: "Max Sessions Reached" }, // agentMaxSessionHoldCount
  26. UnknownDeviceGroup: { description: "Unknown Device Group" }, // (invalidDomainMeshCount + invalidDomainMesh2Count)
  27. InvalidDeviceGroupType: { description: "Invalid Device Group Type" }, // invalidMeshTypeCount
  28. DuplicateAgent: { description: "Duplicate Agent" }, // duplicateAgentCount
  29. blockedUsers: { description: "Blocked Users" }, // blockedUsers
  30. blockedAgents: { description: "Blocked Agents" }, // blockedAgents
  31. };
  32. obj.gaugeMetrics = { // Gauge Metrics always start at 0 and can increase and decrease
  33. ConnectedIntelAMT: { description: "Connected Intel AMT" }, // parent.parent.connectivityByNode[i].connectivity == 4
  34. ConnectedIntelAMTCira: { description: "Connected Intel AMT CIRA" }, // parent.mpsserver.ciraConnections[i].length
  35. UserAccounts: { description: "User Accounts" }, // Object.keys(parent.webserver.users).length
  36. DeviceGroups: { description: "Device Groups" }, // parent.webserver.meshes (ONLY WHERE deleted=null)
  37. AgentSessions: { description: "Agent Sessions" }, // Object.keys(parent.webserver.wsagents).length
  38. ConnectedUsers: { description: "Connected Users" }, // Object.keys(parent.webserver.wssessions).length
  39. UsersSessions: { description: "Users Sessions" }, // Object.keys(parent.webserver.wssessions2).length
  40. RelaySessions: { description: "Relay Sessions" }, // parent.webserver.relaySessionCount
  41. RelayCount: { description: "Relay Count" } // Object.keys(parent.webserver.wsrelays).length30bb4fb74dfb758d36be52a7
  42. }
  43. obj.collectors = [];
  44. if (parent.config.settings.prometheus != null) { // Create Prometheus Monitoring Endpoint
  45. if ((typeof parent.config.settings.prometheus == 'number') && ((parent.config.settings.prometheus < 1) || (parent.config.settings.prometheus > 65535))) {
  46. console.log('Promethus port number is invalid, Prometheus metrics endpoint has be disabled');
  47. delete parent.config.settings.prometheus;
  48. } else {
  49. const port = ((typeof parent.config.settings.prometheus == 'number') ? parent.config.settings.prometheus : 9464);
  50. obj.prometheus = require('prom-client');
  51. const collectDefaultMetrics = obj.prometheus.collectDefaultMetrics;
  52. collectDefaultMetrics();
  53. for (const key in obj.gaugeMetrics) {
  54. obj.gaugeMetrics[key].prometheus = new obj.prometheus.Gauge({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.gaugeMetrics[key].description });
  55. }
  56. for (const key in obj.counterMetrics) {
  57. obj.counterMetrics[key].prometheus = new obj.prometheus.Counter({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.counterMetrics[key].description });
  58. }
  59. obj.app.get('/', function (req, res) { res.send('MeshCentral Prometheus server.'); });
  60. obj.app.listen(port, function () {
  61. console.log('MeshCentral Prometheus server running on port ' + port + '.');
  62. obj.parent.updateServerState('prometheus-port', port);
  63. });
  64. obj.app.get('/metrics', async (req, res) => {
  65. try {
  66. // Count the number of device groups that are not deleted
  67. var activeDeviceGroups = 0;
  68. for (var i in parent.webserver.meshes) { if (parent.webserver.meshes[i].deleted == null) { activeDeviceGroups++; } } // This is not ideal for performance, we want to dome something better.
  69. var gauges = {
  70. UserAccounts: Object.keys(parent.webserver.users).length,
  71. DeviceGroups: activeDeviceGroups,
  72. AgentSessions: Object.keys(parent.webserver.wsagents).length,
  73. ConnectedUsers: Object.keys(parent.webserver.wssessions).length,
  74. UsersSessions: Object.keys(parent.webserver.wssessions2).length,
  75. RelaySessions: parent.webserver.relaySessionCount,
  76. RelayCount: Object.keys(parent.webserver.wsrelays).length,
  77. ConnectedIntelAMT: 0
  78. };
  79. if (parent.mpsserver != null) {
  80. gauges.ConnectedIntelAMTCira = 0;
  81. for (var i in parent.mpsserver.ciraConnections) {
  82. gauges.ConnectedIntelAMTCira += parent.mpsserver.ciraConnections[i].length;
  83. }
  84. }
  85. for (var i in parent.connectivityByNode) {
  86. const node = parent.connectivityByNode[i];
  87. if (node && typeof node.connectivity !== 'undefined' && node.connectivity === 4) { gauges.ConnectedIntelAMT++; }
  88. }
  89. for (const key in gauges) { obj.gaugeMetrics[key].prometheus.set(gauges[key]); }
  90. // Take a look at agent errors
  91. var agentstats = parent.webserver.getAgentStats();
  92. const counters = {
  93. RelayErrors: parent.webserver.relaySessionErrorCount,
  94. UnknownGroup: agentstats.meshDoesNotExistCount,
  95. InvalidPKCSsignature: agentstats.invalidPkcsSignatureCount,
  96. InvalidRSAsignature: agentstats.invalidRsaSignatureCount,
  97. InvalidJSON: agentstats.invalidJsonCount,
  98. UnknownAction: agentstats.unknownAgentActionCount,
  99. BadWebCertificate: agentstats.agentBadWebCertHashCount,
  100. BadSignature: (agentstats.agentBadSignature1Count + agentstats.agentBadSignature2Count),
  101. MaxSessionsReached: agentstats.agentMaxSessionHoldCount,
  102. UnknownDeviceGroup: (agentstats.invalidDomainMeshCount + agentstats.invalidDomainMesh2Count),
  103. InvalidDeviceGroupType: (agentstats.invalidMeshTypeCount + agentstats.invalidMeshType2Count),
  104. DuplicateAgent: agentstats.duplicateAgentCount,
  105. blockedUsers: parent.webserver.blockedUsers,
  106. blockedAgents: parent.webserver.blockedAgents
  107. };
  108. for (const key in counters) { obj.counterMetrics[key].prometheus.reset(); obj.counterMetrics[key].prometheus.inc(counters[key]); }
  109. res.set('Content-Type', obj.prometheus.register.contentType);
  110. await Promise.all(obj.collectors.map((collector) => (collector(req, res))));
  111. res.end(await obj.prometheus.register.metrics());
  112. } catch (ex) {
  113. console.log(ex);
  114. res.status(500).end();
  115. }
  116. });
  117. }
  118. }
  119. return obj;
  120. }