2025-01-02 23:38:13 +00:00
/ * *
* @ description MeshCentral monitoring module
* @ author Simon Smith
* @ license Apache - 2.0
* @ version v0 . 0.1
* /
"use strict" ;
module . exports . CreateMonitoring = function ( parent , args ) {
var obj = { } ;
obj . args = args ;
obj . parent = parent ;
obj . express = require ( 'express' ) ;
obj . app = obj . express ( ) ;
obj . prometheus = null ;
if ( args . compression !== false ) { obj . app . use ( require ( 'compression' ) ( ) ) ; }
obj . app . disable ( 'x-powered-by' ) ;
obj . counterMetrics = { // Counter Metrics always start at 0 and increase but never decrease
RelayErrors : { description : "Relay Errors" } , // parent.webserver.relaySessionErrorCount
UnknownGroup : { description : "Unknown Group" } , // meshDoesNotExistCount
InvalidPKCSsignature : { description : "Invalid PKCS signature" } , // invalidPkcsSignatureCount
InvalidRSAsignature : { description : "Invalid RSA signature" } , // invalidRsaSignatureCount
InvalidJSON : { description : "Invalid JSON" } , // invalidJsonCount
UnknownAction : { description : "Unknown Action" } , // unknownAgentActionCount
BadWebCertificate : { description : "Bad Web Certificate" } , // agentBadWebCertHashCount
BadSignature : { description : "Bad Signature" } , // (agentBadSignature1Count + agentBadSignature2Count)
MaxSessionsReached : { description : "Max Sessions Reached" } , // agentMaxSessionHoldCount
UnknownDeviceGroup : { description : "Unknown Device Group" } , // (invalidDomainMeshCount + invalidDomainMesh2Count)
InvalidDeviceGroupType : { description : "Invalid Device Group Type" } , // invalidMeshTypeCount
DuplicateAgent : { description : "Duplicate Agent" } , // duplicateAgentCount
blockedUsers : { description : "Blocked Users" } , // blockedUsers
blockedAgents : { description : "Blocked Agents" } , // blockedAgents
} ;
2025-02-20 22:59:36 +01:00
obj . gaugeMetrics = { // Gauge Metrics always start at 0 and can increase and decrease
2025-01-02 23:38:13 +00:00
ConnectedIntelAMT : { description : "Connected Intel AMT" } , // parent.mpsserver.ciraConnections[i].length
UserAccounts : { description : "User Accounts" } , // Object.keys(parent.webserver.users).length
DeviceGroups : { description : "Device Groups" } , // parent.webserver.meshes (ONLY WHERE deleted=null)
AgentSessions : { description : "Agent Sessions" } , // Object.keys(parent.webserver.wsagents).length
ConnectedUsers : { description : "Connected Users" } , // Object.keys(parent.webserver.wssessions).length
UsersSessions : { description : "Users Sessions" } , // Object.keys(parent.webserver.wssessions2).length
RelaySessions : { description : "Relay Sessions" } , // parent.webserver.relaySessionCount
RelayCount : { description : "Relay Count" } // Object.keys(parent.webserver.wsrelays).length30bb4fb74dfb758d36be52a7
}
if ( parent . config . settings . prometheus != null ) { // Create Prometheus Monitoring Endpoint
if ( ( typeof parent . config . settings . prometheus == 'number' ) && ( ( parent . config . settings . prometheus < 1 ) || ( parent . config . settings . prometheus > 65535 ) ) ) {
console . log ( 'Promethus port number is invalid, Prometheus metrics endpoint has be disabled' ) ;
delete parent . config . settings . prometheus ;
} else {
const port = ( ( typeof parent . config . settings . prometheus == 'number' ) ? parent . config . settings . prometheus : 9464 ) ;
obj . prometheus = require ( 'prom-client' ) ;
const collectDefaultMetrics = obj . prometheus . collectDefaultMetrics ;
collectDefaultMetrics ( ) ;
2025-02-20 22:59:36 +01:00
for ( const key in obj . gaugeMetrics ) {
obj . gaugeMetrics [ key ] . prometheus = new obj . prometheus . Gauge ( { name : 'meshcentral_' + String ( key ) . toLowerCase ( ) , help : obj . gaugeMetrics [ key ] . description } ) ;
2025-01-02 23:38:13 +00:00
}
for ( const key in obj . counterMetrics ) {
obj . counterMetrics [ key ] . prometheus = new obj . prometheus . Counter ( { name : 'meshcentral_' + String ( key ) . toLowerCase ( ) , help : obj . counterMetrics [ key ] . description } ) ;
}
obj . app . get ( '/' , function ( req , res ) { res . send ( 'MeshCentral Prometheus server.' ) ; } ) ;
obj . app . listen ( port , function ( ) {
console . log ( 'MeshCentral Prometheus server running on port ' + port + '.' ) ;
obj . parent . updateServerState ( 'prometheus-port' , port ) ;
} ) ;
obj . app . get ( '/metrics' , async ( req , res ) => {
try {
// Count the number of device groups that are not deleted
var activeDeviceGroups = 0 ;
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.
2025-02-20 22:59:36 +01:00
var gauges = {
2025-01-02 23:38:13 +00:00
UserAccounts : Object . keys ( parent . webserver . users ) . length ,
DeviceGroups : activeDeviceGroups ,
AgentSessions : Object . keys ( parent . webserver . wsagents ) . length ,
ConnectedUsers : Object . keys ( parent . webserver . wssessions ) . length ,
UsersSessions : Object . keys ( parent . webserver . wssessions2 ) . length ,
RelaySessions : parent . webserver . relaySessionCount ,
RelayCount : Object . keys ( parent . webserver . wsrelays ) . length ,
ConnectedIntelAMT : 0
} ;
if ( parent . mpsserver != null ) {
for ( var i in parent . mpsserver . ciraConnections ) {
2025-02-20 22:59:36 +01:00
gauges . ConnectedIntelAMT += parent . mpsserver . ciraConnections [ i ] . length ;
2025-01-02 23:38:13 +00:00
}
}
2025-02-20 22:59:36 +01:00
for ( const key in gauges ) { obj . gaugeMetrics [ key ] . prometheus . set ( gauges [ key ] ) ; }
2025-01-02 23:38:13 +00:00
// Take a look at agent errors
var agentstats = parent . webserver . getAgentStats ( ) ;
const counters = {
RelayErrors : parent . webserver . relaySessionErrorCount ,
UnknownGroup : agentstats . meshDoesNotExistCount ,
InvalidPKCSsignature : agentstats . invalidPkcsSignatureCount ,
InvalidRSAsignature : agentstats . invalidRsaSignatureCount ,
InvalidJSON : agentstats . invalidJsonCount ,
UnknownAction : agentstats . unknownAgentActionCount ,
BadWebCertificate : agentstats . agentBadWebCertHashCount ,
BadSignature : ( agentstats . agentBadSignature1Count + agentstats . agentBadSignature2Count ) ,
MaxSessionsReached : agentstats . agentMaxSessionHoldCount ,
UnknownDeviceGroup : ( agentstats . invalidDomainMeshCount + agentstats . invalidDomainMesh2Count ) ,
InvalidDeviceGroupType : ( agentstats . invalidMeshTypeCount + agentstats . invalidMeshType2Count ) ,
DuplicateAgent : agentstats . duplicateAgentCount ,
blockedUsers : parent . webserver . blockedUsers ,
blockedAgents : parent . webserver . blockedAgents
} ;
for ( const key in counters ) { obj . counterMetrics [ key ] . prometheus . reset ( ) ; obj . counterMetrics [ key ] . prometheus . inc ( counters [ key ] ) ; }
res . set ( 'Content-Type' , obj . prometheus . register . contentType ) ;
res . end ( await obj . prometheus . register . metrics ( ) ) ;
} catch ( ex ) {
console . log ( ex ) ;
res . status ( 500 ) . end ( ) ;
}
} ) ;
}
}
}