mirror of
https://github.com/edumeet/edumeet.git
synced 2026-01-23 02:34:58 +00:00
fixed prometheus expoter classes with linting
This commit is contained in:
parent
2f04658213
commit
3e61780394
6 changed files with 515 additions and 497 deletions
|
|
@ -6,3 +6,7 @@ listeningPort: 3443
|
|||
listeningRedirectPort: 0
|
||||
httpOnly: false
|
||||
trustProxy: ''
|
||||
|
||||
prometheus:
|
||||
enabled: true
|
||||
listen: 0.0.0.0
|
||||
|
|
|
|||
|
|
@ -335,39 +335,45 @@ const configSchema = convict({
|
|||
},
|
||||
// Prometheus exporter
|
||||
prometheus : {
|
||||
deidentify : {
|
||||
doc : 'De-identify IP addresses in Prometheus logs.',
|
||||
enabled : {
|
||||
doc : 'Enables the Prometheus metrics exporter.',
|
||||
format : 'Boolean',
|
||||
default : false
|
||||
},
|
||||
listen : {
|
||||
doc : 'Prometheus exporter listening address.',
|
||||
doc : 'Prometheus metrics exporter listening address.',
|
||||
format : 'String',
|
||||
default : 'localhost'
|
||||
},
|
||||
port : {
|
||||
doc : 'The Prometheus metrics exporter listening port.',
|
||||
format : 'port',
|
||||
default : 8889
|
||||
},
|
||||
// default metrics options
|
||||
deidentify : {
|
||||
doc : 'De-identify IP addresses in Prometheus logs.',
|
||||
format : 'Boolean',
|
||||
default : false
|
||||
},
|
||||
numeric : {
|
||||
doc : 'Show numeric IP addresses in Prometheus logs.',
|
||||
format : 'Boolean',
|
||||
default : false
|
||||
},
|
||||
port : {
|
||||
doc : 'The Prometheus exporter listening port.',
|
||||
format : 'port',
|
||||
default : 8889
|
||||
},
|
||||
quiet : {
|
||||
doc : 'Include fewer labels in Prometheus logs.',
|
||||
doc : 'Include fewer labels in Prometheus metrics.',
|
||||
format : 'Boolean',
|
||||
default : false
|
||||
},
|
||||
// aggregated metrics options
|
||||
period : {
|
||||
doc : 'The Prometheus exporter update period (seconds).',
|
||||
doc : 'The Prometheus metrics exporter update period (seconds).',
|
||||
format : 'nat',
|
||||
default : 15
|
||||
},
|
||||
secret : {
|
||||
doc : 'The Prometheus exporter authorization header: `Bearer <secret>` required to allow scraping.',
|
||||
doc : 'The Prometheus metrics exporter authorization header: `Bearer <secret>` required to allow scraping.',
|
||||
format : String,
|
||||
default : ''
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,83 +9,88 @@ const logger = new Logger('metrics:aggregated');
|
|||
//
|
||||
module.exports = function(workers, rooms_, peers_, config)
|
||||
{
|
||||
const register = new promClient.Registry();
|
||||
promClient.collectDefaultMetrics({ prefix: 'mediasoup_', register });
|
||||
|
||||
const mediasoupStats = {};
|
||||
let mediasoupStatsUpdate = 0;
|
||||
const register = new promClient.Registry();
|
||||
|
||||
const formatStats = (s) =>
|
||||
{
|
||||
return {
|
||||
length: s.length || 0,
|
||||
sum: s.sum || 0,
|
||||
mean: s.amean() || 0,
|
||||
stddev: s.stddev() || 0,
|
||||
p25: s.percentile(25) || 0,
|
||||
min: s.min || 0,
|
||||
max: s.max || 0,
|
||||
};
|
||||
};
|
||||
promClient.collectDefaultMetrics({ prefix: 'mediasoup_', register });
|
||||
|
||||
const collectStats = async () =>
|
||||
{
|
||||
const now = Date.now();
|
||||
const mediasoupStats = {};
|
||||
let mediasoupStatsUpdate = 0;
|
||||
|
||||
if (now - mediasoupStatsUpdate < config.period * 1000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mediasoupStatsUpdate = now;
|
||||
const formatStats = (s) =>
|
||||
{
|
||||
return {
|
||||
length : s.length || 0,
|
||||
sum : s.sum || 0,
|
||||
mean : s.amean() || 0,
|
||||
stddev : s.stddev() || 0,
|
||||
p25 : s.percentile(25) || 0,
|
||||
min : s.min || 0,
|
||||
max : s.max || 0
|
||||
};
|
||||
};
|
||||
|
||||
const start = process.hrtime();
|
||||
const collectStats = async () =>
|
||||
{
|
||||
const now = Date.now();
|
||||
|
||||
let workers_cpu = new Stats();
|
||||
let workers_memory = new Stats();
|
||||
if (now - mediasoupStatsUpdate < config.period * 1000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mediasoupStatsUpdate = now;
|
||||
|
||||
let rooms = new Stats();
|
||||
rooms.push(rooms_.size);
|
||||
const start = process.hrtime();
|
||||
|
||||
let peers = new Stats();
|
||||
peers.push(peers_.size);
|
||||
const workersCpu = new Stats();
|
||||
const workersMemory = new Stats();
|
||||
|
||||
// in
|
||||
let video_bitrates_in = new Stats();
|
||||
let audio_bitrates_in = new Stats();
|
||||
let video_scores_in = new Stats();
|
||||
let audio_scores_in = new Stats();
|
||||
const rooms = new Stats();
|
||||
|
||||
let packets_counts_in = new Stats();
|
||||
let packets_losts_in = new Stats();
|
||||
let packets_retransmitted_in = new Stats();
|
||||
rooms.push(rooms_.size);
|
||||
|
||||
// out
|
||||
let video_bitrates_out = new Stats();
|
||||
let audio_bitrates_out = new Stats();
|
||||
const peers = new Stats();
|
||||
|
||||
let round_trip_times_out = new Stats();
|
||||
let packets_counts_out = new Stats();
|
||||
let packets_losts_out = new Stats();
|
||||
peers.push(peers_.size);
|
||||
|
||||
let spatial_layers_out = new Stats();
|
||||
let temporal_layers_out = new Stats();
|
||||
// in
|
||||
const videoBitratesIn = new Stats();
|
||||
const audioBitratesIn = new Stats();
|
||||
const videoScoresIn = new Stats();
|
||||
const audioScoresIn = new Stats();
|
||||
|
||||
try {
|
||||
// iterate workers
|
||||
for (const worker of workers.values())
|
||||
{
|
||||
// worker process stats
|
||||
const workerStats = await pidusage(worker._pid);
|
||||
workers_cpu.push(workerStats.cpu / 100);
|
||||
workers_memory.push(workerStats.memory);
|
||||
|
||||
// iterate routers
|
||||
for (const router of worker._routers.values())
|
||||
{
|
||||
// iterate transports
|
||||
for (const transport of router._transports.values())
|
||||
{
|
||||
/* let stats = [];
|
||||
const packetsCountsIn = new Stats();
|
||||
const packetsLostsIn = new Stats();
|
||||
const packetsRetransmittedIn = new Stats();
|
||||
|
||||
// out
|
||||
const videoBitratesOut = new Stats();
|
||||
const audioBitratesOut = new Stats();
|
||||
|
||||
const roundTripTimesOut = new Stats();
|
||||
const packetsCountsOut = new Stats();
|
||||
const packetsLostsOut = new Stats();
|
||||
|
||||
const spatialLayersOut = new Stats();
|
||||
const temporalLayersOut = new Stats();
|
||||
|
||||
try
|
||||
{
|
||||
// iterate workers
|
||||
for (const worker of workers)
|
||||
{
|
||||
// worker process stats
|
||||
const workerStats = await pidusage(worker.pid);
|
||||
|
||||
workersCpu.push(workerStats.cpu / 100);
|
||||
workersMemory.push(workerStats.memory);
|
||||
|
||||
// iterate routers
|
||||
for (const router of worker._routers.values())
|
||||
{
|
||||
// iterate transports
|
||||
for (const transport of router._transports.values())
|
||||
{
|
||||
/* let stats = [];
|
||||
try
|
||||
{
|
||||
stats = await transport.getStats();
|
||||
|
|
@ -102,212 +107,225 @@ module.exports = function(workers, rooms_, peers_, config)
|
|||
}
|
||||
} */
|
||||
|
||||
// iterate producers
|
||||
for (const producer of transport._producers.values())
|
||||
{
|
||||
let stats = [];
|
||||
try
|
||||
{
|
||||
stats = await producer.getStats();
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
logger.error('producer.getStats error:', err.message);
|
||||
continue;
|
||||
}
|
||||
for (const s of stats)
|
||||
{
|
||||
if (s.type !== 'inbound-rtp')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (s.kind === 'video')
|
||||
{
|
||||
video_bitrates_in.push(s.bitrate);
|
||||
video_scores_in.push(s.score);
|
||||
}
|
||||
else if (s.kind === 'audio')
|
||||
{
|
||||
audio_bitrates_in.push(s.bitrate);
|
||||
audio_scores_in.push(s.score);
|
||||
}
|
||||
packets_counts_in.push(s.packetCount || 0);
|
||||
packets_losts_in.push(s.packetsLost || 0);
|
||||
packets_retransmitted_in.push(s.packetsRetransmitted || 0);
|
||||
}
|
||||
}
|
||||
// iterate producers
|
||||
for (const producer of transport._producers.values())
|
||||
{
|
||||
let stats = [];
|
||||
|
||||
// iterate consumers
|
||||
for (const consumer of transport._consumers.values())
|
||||
{
|
||||
if (consumer.type === 'pipe')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let stats = [];
|
||||
try
|
||||
{
|
||||
stats = await consumer.getStats();
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
logger.error('consumer.getStats error:', err.message);
|
||||
continue;
|
||||
}
|
||||
for (const s of stats)
|
||||
{
|
||||
if(s.type !== 'outbound-rtp'){
|
||||
continue;
|
||||
}
|
||||
if (s.kind === 'video')
|
||||
{
|
||||
video_bitrates_out.push(s.bitrate || 0);
|
||||
spatial_layers_out.push(consumer.currentLayers ? consumer.currentLayers.spatialLayer : 0);
|
||||
temporal_layers_out.push(consumer.currentLayers ? consumer.currentLayers.temporalLayer : 0);
|
||||
}
|
||||
else if(s.kind === 'audio')
|
||||
{
|
||||
audio_bitrates_out.push(s.bitrate || 0);
|
||||
}
|
||||
round_trip_times_out.push(s.roundTripTime || 0);
|
||||
packets_counts_out.push(s.packetCount || 0);
|
||||
packets_losts_out.push(s.packetsLost || 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
logger.error('collectStats error:', err.message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Object.assign(mediasoupStats, {
|
||||
workers_cpu: formatStats(workers_cpu),
|
||||
workers_memory: formatStats(workers_memory),
|
||||
rooms: formatStats(rooms),
|
||||
peers: formatStats(peers),
|
||||
// in
|
||||
video_bitrates_in: formatStats(video_bitrates_in),
|
||||
video_scores_in: formatStats(video_scores_in),
|
||||
audio_bitrates_in: formatStats(audio_bitrates_in),
|
||||
audio_scores_in: formatStats(audio_scores_in),
|
||||
packets_counts_in: formatStats(packets_counts_in),
|
||||
packets_losts_in: formatStats(packets_losts_in),
|
||||
packets_retransmitted_in: formatStats(packets_retransmitted_in),
|
||||
// out
|
||||
video_bitrates_out: formatStats(video_bitrates_out),
|
||||
audio_bitrates_out: formatStats(audio_bitrates_out),
|
||||
round_trip_times_out: formatStats(round_trip_times_out),
|
||||
packets_counts_out: formatStats(packets_counts_out),
|
||||
packets_losts_out: formatStats(packets_losts_out),
|
||||
spatial_layers_out: formatStats(spatial_layers_out),
|
||||
temporal_layers_out: formatStats(temporal_layers_out),
|
||||
});
|
||||
}
|
||||
try
|
||||
{
|
||||
stats = await producer.getStats();
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
logger.error('producer.getStats error:', err.message);
|
||||
continue;
|
||||
}
|
||||
for (const s of stats)
|
||||
{
|
||||
if (s.type !== 'inbound-rtp')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (s.kind === 'video')
|
||||
{
|
||||
videoBitratesIn.push(s.bitrate);
|
||||
videoScoresIn.push(s.score);
|
||||
}
|
||||
else if (s.kind === 'audio')
|
||||
{
|
||||
audioBitratesIn.push(s.bitrate);
|
||||
audioScoresIn.push(s.score);
|
||||
}
|
||||
packetsCountsIn.push(s.packetCount || 0);
|
||||
packetsLostsIn.push(s.packetsLost || 0);
|
||||
packetsRetransmittedIn.push(s.packetsRetransmitted || 0);
|
||||
}
|
||||
}
|
||||
|
||||
const end = process.hrtime(start);
|
||||
logger.info(`collectStats (elapsed: ${end[0] * 1e3 + end[1] * 1e-6} ms)`);
|
||||
}
|
||||
// iterate consumers
|
||||
for (const consumer of transport._consumers.values())
|
||||
{
|
||||
if (consumer.type === 'pipe')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let stats = [];
|
||||
|
||||
// mediasoup metrics
|
||||
[
|
||||
{ name: 'workers_count', statName: 'workers_cpu', statValue: 'length' },
|
||||
{ name: 'workers_cpu', statName: 'workers_cpu', statValue: 'sum' },
|
||||
{ name: 'workers_memory', statName: 'workers_memory', statValue: 'sum' },
|
||||
//
|
||||
{ name: 'rooms', statName: 'rooms', statValue: 'sum' },
|
||||
{ name: 'peers', statName: 'peers', statValue: 'sum' },
|
||||
// audio in
|
||||
{ name: 'audio_in_count', statName: 'audio_bitrates_in', statValue: 'length' },
|
||||
// audio in bitrates
|
||||
{ name: 'audio_bitrates_in_sum', statName: 'audio_bitrates_in', statValue: 'sum' },
|
||||
{ name: 'audio_bitrates_in_mean', statName: 'audio_bitrates_in', statValue: 'mean' },
|
||||
{ name: 'audio_bitrates_in_min', statName: 'audio_bitrates_in', statValue: 'min' },
|
||||
{ name: 'audio_bitrates_in_max', statName: 'audio_bitrates_in', statValue: 'max' },
|
||||
{ name: 'audio_bitrates_in_p25', statName: 'audio_bitrates_in', statValue: 'p25' },
|
||||
// audio in scores
|
||||
{ name: 'audio_scores_in_mean', statName: 'audio_scores_in', statValue: 'mean' },
|
||||
{ name: 'audio_scores_in_min', statName: 'audio_scores_in', statValue: 'min' },
|
||||
{ name: 'audio_scores_in_max', statName: 'audio_scores_in', statValue: 'max' },
|
||||
{ name: 'audio_scores_in_p25', statName: 'audio_scores_in', statValue: 'p25' },
|
||||
// video in
|
||||
{ name: 'video_in_count', statName: 'video_bitrates_in', statValue: 'length' },
|
||||
// video in bitrates
|
||||
{ name: 'video_bitrates_in_sum', statName: 'video_bitrates_in', statValue: 'sum' },
|
||||
{ name: 'video_bitrates_in_mean', statName: 'video_bitrates_in', statValue: 'mean' },
|
||||
{ name: 'video_bitrates_in_min', statName: 'video_bitrates_in', statValue: 'min' },
|
||||
{ name: 'video_bitrates_in_max', statName: 'video_bitrates_in', statValue: 'max' },
|
||||
{ name: 'video_bitrates_in_p25', statName: 'video_bitrates_in', statValue: 'p25' },
|
||||
// video in scores
|
||||
{ name: 'video_scores_in_mean', statName: 'video_scores_in', statValue: 'mean' },
|
||||
{ name: 'video_scores_in_min', statName: 'video_scores_in', statValue: 'min' },
|
||||
{ name: 'video_scores_in_max', statName: 'video_scores_in', statValue: 'max' },
|
||||
{ name: 'video_scores_in_p25', statName: 'video_scores_in', statValue: 'p25' },
|
||||
// packets in
|
||||
{ name: 'packets_counts_in_sum', statName: 'packets_counts_in', statValue: 'sum' },
|
||||
{ name: 'packets_counts_in_mean', statName: 'packets_counts_in', statValue: 'mean' },
|
||||
{ name: 'packets_counts_in_min', statName: 'packets_counts_in', statValue: 'min' },
|
||||
{ name: 'packets_counts_in_max', statName: 'packets_counts_in', statValue: 'max' },
|
||||
{ name: 'packets_counts_in_p25', statName: 'packets_counts_in', statValue: 'p25' },
|
||||
{ name: 'packets_losts_in_sum', statName: 'packets_losts_in', statValue: 'sum' },
|
||||
{ name: 'packets_losts_in_mean', statName: 'packets_losts_in', statValue: 'mean' },
|
||||
{ name: 'packets_losts_in_min', statName: 'packets_losts_in', statValue: 'min' },
|
||||
{ name: 'packets_losts_in_max', statName: 'packets_losts_in', statValue: 'max' },
|
||||
{ name: 'packets_losts_in_p25', statName: 'packets_losts_in', statValue: 'p25' },
|
||||
{ name: 'packets_retransmitted_in_sum', statName: 'packets_retransmitted_in', statValue: 'sum' },
|
||||
{ name: 'packets_retransmitted_in_mean', statName: 'packets_retransmitted_in', statValue: 'mean' },
|
||||
{ name: 'packets_retransmitted_in_min', statName: 'packets_retransmitted_in', statValue: 'min' },
|
||||
{ name: 'packets_retransmitted_in_max', statName: 'packets_retransmitted_in', statValue: 'max' },
|
||||
{ name: 'packets_retransmitted_in_p25', statName: 'packets_retransmitted_in', statValue: 'p25' },
|
||||
// audio out
|
||||
{ name: 'audio_out_count', statName: 'audio_bitrates_out', statValue: 'length' },
|
||||
{ name: 'audio_bitrates_out_sum', statName: 'audio_bitrates_out', statValue: 'sum' },
|
||||
{ name: 'audio_bitrates_out_mean', statName: 'audio_bitrates_out', statValue: 'mean' },
|
||||
{ name: 'audio_bitrates_out_min', statName: 'audio_bitrates_out', statValue: 'min' },
|
||||
{ name: 'audio_bitrates_out_max', statName: 'audio_bitrates_out', statValue: 'max' },
|
||||
{ name: 'audio_bitrates_out_p25', statName: 'audio_bitrates_out', statValue: 'p25' },
|
||||
// video out
|
||||
{ name: 'video_out_count', statName: 'video_bitrates_out', statValue: 'length' },
|
||||
{ name: 'video_bitrates_out_sum', statName: 'video_bitrates_out', statValue: 'sum' },
|
||||
{ name: 'video_bitrates_out_mean', statName: 'video_bitrates_out', statValue: 'mean' },
|
||||
{ name: 'video_bitrates_out_min', statName: 'video_bitrates_out', statValue: 'min' },
|
||||
{ name: 'video_bitrates_out_max', statName: 'video_bitrates_out', statValue: 'max' },
|
||||
{ name: 'video_bitrates_out_p25', statName: 'video_bitrates_out', statValue: 'p25' },
|
||||
// sl
|
||||
{ name: 'spatial_layers_out_mean', statName: 'spatial_layers_out', statValue: 'mean' },
|
||||
{ name: 'spatial_layers_out_min', statName: 'spatial_layers_out', statValue: 'min' },
|
||||
{ name: 'spatial_layers_out_max', statName: 'spatial_layers_out', statValue: 'max' },
|
||||
{ name: 'spatial_layers_out_p25', statName: 'spatial_layers_out', statValue: 'p25' },
|
||||
// tl
|
||||
{ name: 'temporal_layers_out_mean', statName: 'temporal_layers_out', statValue: 'mean' },
|
||||
{ name: 'temporal_layers_out_min', statName: 'temporal_layers_out', statValue: 'min' },
|
||||
{ name: 'temporal_layers_out_max', statName: 'temporal_layers_out', statValue: 'max' },
|
||||
{ name: 'temporal_layers_out_p25', statName: 'temporal_layers_out', statValue: 'p25' },
|
||||
// rtt out
|
||||
{ name: 'round_trip_times_out_mean', statName: 'round_trip_times_out', statValue: 'mean' },
|
||||
{ name: 'round_trip_times_out_min', statName: 'round_trip_times_out', statValue: 'min' },
|
||||
{ name: 'round_trip_times_out_max', statName: 'round_trip_times_out', statValue: 'max' },
|
||||
{ name: 'round_trip_times_out_p25', statName: 'round_trip_times_out', statValue: 'p25' },
|
||||
try
|
||||
{
|
||||
stats = await consumer.getStats();
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
logger.error('consumer.getStats error:', err.message);
|
||||
continue;
|
||||
}
|
||||
for (const s of stats)
|
||||
{
|
||||
if (s.type !== 'outbound-rtp')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (s.kind === 'video')
|
||||
{
|
||||
videoBitratesOut.push(s.bitrate || 0);
|
||||
spatialLayersOut.push(consumer.currentLayers
|
||||
? consumer.currentLayers.spatialLayer : 0);
|
||||
temporalLayersOut.push(consumer.currentLayers
|
||||
? consumer.currentLayers.temporalLayer : 0);
|
||||
}
|
||||
else if (s.kind === 'audio')
|
||||
{
|
||||
audioBitratesOut.push(s.bitrate || 0);
|
||||
}
|
||||
roundTripTimesOut.push(s.roundTripTime || 0);
|
||||
packetsCountsOut.push(s.packetCount || 0);
|
||||
packetsLostsOut.push(s.packetsLost || 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
logger.error('collectStats error:', err.message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Object.assign(mediasoupStats, {
|
||||
workersCpu : formatStats(workersCpu),
|
||||
workersMemory : formatStats(workersMemory),
|
||||
rooms : formatStats(rooms),
|
||||
peers : formatStats(peers),
|
||||
// in
|
||||
videoBitratesIn : formatStats(videoBitratesIn),
|
||||
videoScoresIn : formatStats(videoScoresIn),
|
||||
audioBitratesIn : formatStats(audioBitratesIn),
|
||||
audioScoresIn : formatStats(audioScoresIn),
|
||||
packetsCountsIn : formatStats(packetsCountsIn),
|
||||
packetsLostsIn : formatStats(packetsLostsIn),
|
||||
packetsRetransmittedIn : formatStats(packetsRetransmittedIn),
|
||||
// out
|
||||
videoBitratesOut : formatStats(videoBitratesOut),
|
||||
audioBitratesOut : formatStats(audioBitratesOut),
|
||||
roundTripTimesOut : formatStats(roundTripTimesOut),
|
||||
packetsCountsOut : formatStats(packetsCountsOut),
|
||||
packetsLostsOut : formatStats(packetsLostsOut),
|
||||
spatialLayersOut : formatStats(spatialLayersOut),
|
||||
temporalLayersOut : formatStats(temporalLayersOut)
|
||||
});
|
||||
}
|
||||
|
||||
].forEach(({ name, statName, statValue }) => {
|
||||
new promClient.Gauge({
|
||||
name: `mediasoup_${name}`,
|
||||
help: `MediaSoup ${name}`,
|
||||
labelNames: [],
|
||||
registers: [ register ],
|
||||
async collect()
|
||||
{
|
||||
await collectStats();
|
||||
if (mediasoupStats[statName] !== undefined && mediasoupStats[statName][statValue] !== undefined)
|
||||
{
|
||||
this.set({}, mediasoupStats[statName][statValue]);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
const end = process.hrtime(start);
|
||||
|
||||
return register;
|
||||
logger.info(`collectStats (elapsed: ${(end[0] * 1e3) + (end[1] * 1e-6)} ms)`);
|
||||
};
|
||||
|
||||
// mediasoup metrics
|
||||
[
|
||||
{ name: 'workers_count', statName: 'workersCpu', statValue: 'length' },
|
||||
{ name: 'workers_cpu', statName: 'workersCpu', statValue: 'sum' },
|
||||
{ name: 'workers_memory', statName: 'workersMemory', statValue: 'sum' },
|
||||
//
|
||||
{ name: 'rooms', statName: 'rooms', statValue: 'sum' },
|
||||
{ name: 'peers', statName: 'peers', statValue: 'sum' },
|
||||
// audio in
|
||||
{ name: 'audio_in_count', statName: 'audioBitratesIn', statValue: 'length' },
|
||||
// audio in bitrates
|
||||
{ name: 'audio_bitrates_in_sum', statName: 'audioBitratesIn', statValue: 'sum' },
|
||||
{ name: 'audio_bitrates_in_mean', statName: 'audioBitratesIn', statValue: 'mean' },
|
||||
{ name: 'audio_bitrates_in_min', statName: 'audioBitratesIn', statValue: 'min' },
|
||||
{ name: 'audio_bitrates_in_max', statName: 'audioBitratesIn', statValue: 'max' },
|
||||
{ name: 'audio_bitrates_in_p25', statName: 'audioBitratesIn', statValue: 'p25' },
|
||||
// audio in scores
|
||||
{ name: 'audio_scores_in_mean', statName: 'audioScoresIn', statValue: 'mean' },
|
||||
{ name: 'audio_scores_in_min', statName: 'audioScoresIn', statValue: 'min' },
|
||||
{ name: 'audio_scores_in_max', statName: 'audioScoresIn', statValue: 'max' },
|
||||
{ name: 'audio_scores_in_p25', statName: 'audioScoresIn', statValue: 'p25' },
|
||||
// video in
|
||||
{ name: 'video_in_count', statName: 'videoBitratesIn', statValue: 'length' },
|
||||
// video in bitrates
|
||||
{ name: 'video_bitrates_in_sum', statName: 'videoBitratesIn', statValue: 'sum' },
|
||||
{ name: 'video_bitrates_in_mean', statName: 'videoBitratesIn', statValue: 'mean' },
|
||||
{ name: 'video_bitrates_in_min', statName: 'videoBitratesIn', statValue: 'min' },
|
||||
{ name: 'video_bitrates_in_max', statName: 'videoBitratesIn', statValue: 'max' },
|
||||
{ name: 'video_bitrates_in_p25', statName: 'videoBitratesIn', statValue: 'p25' },
|
||||
// video in scores
|
||||
{ name: 'video_scores_in_mean', statName: 'videoScoresIn', statValue: 'mean' },
|
||||
{ name: 'video_scores_in_min', statName: 'videoScoresIn', statValue: 'min' },
|
||||
{ name: 'video_scores_in_max', statName: 'videoScoresIn', statValue: 'max' },
|
||||
{ name: 'video_scores_in_p25', statName: 'videoScoresIn', statValue: 'p25' },
|
||||
// packets in
|
||||
{ name: 'packets_counts_in_sum', statName: 'packetsCountsIn', statValue: 'sum' },
|
||||
{ name: 'packets_counts_in_mean', statName: 'packetsCountsIn', statValue: 'mean' },
|
||||
{ name: 'packets_counts_in_min', statName: 'packetsCountsIn', statValue: 'min' },
|
||||
{ name: 'packets_counts_in_max', statName: 'packetsCountsIn', statValue: 'max' },
|
||||
{ name: 'packets_counts_in_p25', statName: 'packetsCountsIn', statValue: 'p25' },
|
||||
{ name: 'packets_losts_in_sum', statName: 'packetsLostsIn', statValue: 'sum' },
|
||||
{ name: 'packets_losts_in_mean', statName: 'packetsLostsIn', statValue: 'mean' },
|
||||
{ name: 'packets_losts_in_min', statName: 'packetsLostsIn', statValue: 'min' },
|
||||
{ name: 'packets_losts_in_max', statName: 'packetsLostsIn', statValue: 'max' },
|
||||
{ name: 'packets_losts_in_p25', statName: 'packetsLostsIn', statValue: 'p25' },
|
||||
{ name: 'packets_retransmitted_in_sum', statName: 'packetsRetransmittedIn', statValue: 'sum' },
|
||||
{ name: 'packets_retransmitted_in_mean', statName: 'packetsRetransmittedIn', statValue: 'mean' },
|
||||
{ name: 'packets_retransmitted_in_min', statName: 'packetsRetransmittedIn', statValue: 'min' },
|
||||
{ name: 'packets_retransmitted_in_max', statName: 'packetsRetransmittedIn', statValue: 'max' },
|
||||
{ name: 'packets_retransmitted_in_p25', statName: 'packetsRetransmittedIn', statValue: 'p25' },
|
||||
// audio out
|
||||
{ name: 'audio_out_count', statName: 'audioBitratesOut', statValue: 'length' },
|
||||
{ name: 'audio_bitrates_out_sum', statName: 'audioBitratesOut', statValue: 'sum' },
|
||||
{ name: 'audio_bitrates_out_mean', statName: 'audioBitratesOut', statValue: 'mean' },
|
||||
{ name: 'audio_bitrates_out_min', statName: 'audioBitratesOut', statValue: 'min' },
|
||||
{ name: 'audio_bitrates_out_max', statName: 'audioBitratesOut', statValue: 'max' },
|
||||
{ name: 'audio_bitrates_out_p25', statName: 'audioBitratesOut', statValue: 'p25' },
|
||||
// video out
|
||||
{ name: 'video_out_count', statName: 'videoBitratesOut', statValue: 'length' },
|
||||
{ name: 'video_bitrates_out_sum', statName: 'videoBitratesOut', statValue: 'sum' },
|
||||
{ name: 'video_bitrates_out_mean', statName: 'videoBitratesOut', statValue: 'mean' },
|
||||
{ name: 'video_bitrates_out_min', statName: 'videoBitratesOut', statValue: 'min' },
|
||||
{ name: 'video_bitrates_out_max', statName: 'videoBitratesOut', statValue: 'max' },
|
||||
{ name: 'video_bitrates_out_p25', statName: 'videoBitratesOut', statValue: 'p25' },
|
||||
// sl
|
||||
{ name: 'spatial_layers_out_mean', statName: 'spatialLayersOut', statValue: 'mean' },
|
||||
{ name: 'spatial_layers_out_min', statName: 'spatialLayersOut', statValue: 'min' },
|
||||
{ name: 'spatial_layers_out_max', statName: 'spatialLayersOut', statValue: 'max' },
|
||||
{ name: 'spatial_layers_out_p25', statName: 'spatialLayersOut', statValue: 'p25' },
|
||||
// tl
|
||||
{ name: 'temporal_layers_out_mean', statName: 'temporalLayersOut', statValue: 'mean' },
|
||||
{ name: 'temporal_layers_out_min', statName: 'temporalLayersOut', statValue: 'min' },
|
||||
{ name: 'temporal_layers_out_max', statName: 'temporalLayersOut', statValue: 'max' },
|
||||
{ name: 'temporal_layers_out_p25', statName: 'temporalLayersOut', statValue: 'p25' },
|
||||
// rtt out
|
||||
{ name: 'round_trip_times_out_mean', statName: 'roundTripTimesOut', statValue: 'mean' },
|
||||
{ name: 'round_trip_times_out_min', statName: 'roundTripTimesOut', statValue: 'min' },
|
||||
{ name: 'round_trip_times_out_max', statName: 'roundTripTimesOut', statValue: 'max' },
|
||||
{ name: 'round_trip_times_out_p25', statName: 'roundTripTimesOut', statValue: 'p25' }
|
||||
|
||||
].forEach(({ name, statName, statValue }) =>
|
||||
{
|
||||
// eslint-disable-next-line no-new
|
||||
new promClient.Gauge({
|
||||
name : `mediasoup_${name}`,
|
||||
help : `MediaSoup ${name}`,
|
||||
labelNames : [],
|
||||
registers : [ register ],
|
||||
async collect()
|
||||
{
|
||||
await collectStats();
|
||||
if (mediasoupStats[statName] !== undefined
|
||||
&& mediasoupStats[statName][statValue] !== undefined)
|
||||
{
|
||||
this.set({}, mediasoupStats[statName][statValue]);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn(`${statName}.${statValue} not found`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return register;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,218 +19,218 @@ const metadata = {
|
|||
|
||||
module.exports = async function(workers, rooms, peers, registry, config)
|
||||
{
|
||||
const newMetrics = function(subsystem)
|
||||
{
|
||||
const namespace = 'mediasoup';
|
||||
const metrics = new Map();
|
||||
const newMetrics = function(subsystem)
|
||||
{
|
||||
const namespace = 'mediasoup';
|
||||
const metrics = new Map();
|
||||
|
||||
for (const key in metadata)
|
||||
{
|
||||
if (Object.prototype.hasOwnProperty.call(metadata, key))
|
||||
{
|
||||
const value = metadata[key];
|
||||
const name = key.split(/(?=[A-Z])/).join('_')
|
||||
.toLowerCase();
|
||||
const unit = value.unit;
|
||||
const metricType = value.metricType;
|
||||
let s = `${namespace}_${subsystem}_${name}`;
|
||||
for (const key in metadata)
|
||||
{
|
||||
if (Object.prototype.hasOwnProperty.call(metadata, key))
|
||||
{
|
||||
const value = metadata[key];
|
||||
const name = key.split(/(?=[A-Z])/).join('_')
|
||||
.toLowerCase();
|
||||
const unit = value.unit;
|
||||
const metricType = value.metricType;
|
||||
let s = `${namespace}_${subsystem}_${name}`;
|
||||
|
||||
if (unit)
|
||||
{
|
||||
s += `_${unit}`;
|
||||
}
|
||||
const m = new metricType({
|
||||
name : s, help : `${subsystem}.${key}`, labelNames : labelNames, registers : [ registry ] });
|
||||
if (unit)
|
||||
{
|
||||
s += `_${unit}`;
|
||||
}
|
||||
const m = new metricType({
|
||||
name : s, help : `${subsystem}.${key}`, labelNames : labelNames, registers : [ registry ] });
|
||||
|
||||
metrics.set(key, m);
|
||||
}
|
||||
}
|
||||
metrics.set(key, m);
|
||||
}
|
||||
}
|
||||
|
||||
return metrics;
|
||||
};
|
||||
return metrics;
|
||||
};
|
||||
|
||||
const commonLabels = function(both, fn)
|
||||
{
|
||||
for (const roomId of rooms.keys())
|
||||
{
|
||||
for (const [ peerId, peer ] of peers)
|
||||
{
|
||||
if (fn(peer))
|
||||
{
|
||||
const displayName = peer._displayName;
|
||||
const userAgent = peer._socket.client.request.headers['user-agent'];
|
||||
const kind = both.kind;
|
||||
const codec = both.rtpParameters.codecs[0].mimeType.split('/')[1];
|
||||
const commonLabels = function(both, fn)
|
||||
{
|
||||
for (const roomId of rooms.keys())
|
||||
{
|
||||
for (const [ peerId, peer ] of peers)
|
||||
{
|
||||
if (fn(peer))
|
||||
{
|
||||
const displayName = peer._displayName;
|
||||
const userAgent = peer._socket.client.request.headers['user-agent'];
|
||||
const kind = both.kind;
|
||||
const codec = both.rtpParameters.codecs[0].mimeType.split('/')[1];
|
||||
|
||||
return { roomId, peerId, displayName, userAgent, kind, codec };
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error('cannot find common labels');
|
||||
};
|
||||
return { roomId, peerId, displayName, userAgent, kind, codec };
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error('cannot find common labels');
|
||||
};
|
||||
|
||||
const addr = async function(ip, port)
|
||||
{
|
||||
if (config.deidentify)
|
||||
{
|
||||
const a = ip.split('.');
|
||||
const addr = async function(ip, port)
|
||||
{
|
||||
if (config.deidentify)
|
||||
{
|
||||
const a = ip.split('.');
|
||||
|
||||
for (let i = 0; i < a.length - 2; i++)
|
||||
{
|
||||
a[i] = 'xx';
|
||||
}
|
||||
for (let i = 0; i < a.length - 2; i++)
|
||||
{
|
||||
a[i] = 'xx';
|
||||
}
|
||||
|
||||
return `${a.join('.')}:${port}`;
|
||||
}
|
||||
else if (config.numeric)
|
||||
{
|
||||
return `${ip}:${port}`;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
const a = await resolver.reverse(ip);
|
||||
return `${a.join('.')}:${port}`;
|
||||
}
|
||||
else if (config.numeric)
|
||||
{
|
||||
return `${ip}:${port}`;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
const a = await resolver.reverse(ip);
|
||||
|
||||
ip = a[0];
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
logger.error(`reverse DNS query failed: ${ip} ${err.code}`);
|
||||
}
|
||||
ip = a[0];
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
logger.error(`reverse DNS query failed: ${ip} ${err.code}`);
|
||||
}
|
||||
|
||||
return `${ip}:${port}`;
|
||||
}
|
||||
};
|
||||
return `${ip}:${port}`;
|
||||
}
|
||||
};
|
||||
|
||||
const quiet = function(s)
|
||||
{
|
||||
return config.quiet ? '' : s;
|
||||
};
|
||||
const quiet = function(s)
|
||||
{
|
||||
return config.quiet ? '' : s;
|
||||
};
|
||||
|
||||
const setValue = function(key, m, labels, v)
|
||||
{
|
||||
logger.debug(`setValue key=${key} v=${v}`);
|
||||
switch (metadata[key].metricType)
|
||||
{
|
||||
case prom.Counter:
|
||||
m.inc(labels, v);
|
||||
break;
|
||||
case prom.Gauge:
|
||||
m.set(labels, v);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unexpected metric: ${m}`);
|
||||
}
|
||||
};
|
||||
const setValue = function(key, m, labels, v)
|
||||
{
|
||||
logger.debug(`setValue key=${key} v=${v}`);
|
||||
switch (metadata[key].metricType)
|
||||
{
|
||||
case prom.Counter:
|
||||
m.inc(labels, v);
|
||||
break;
|
||||
case prom.Gauge:
|
||||
m.set(labels, v);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unexpected metric: ${m}`);
|
||||
}
|
||||
};
|
||||
|
||||
logger.debug('collect');
|
||||
const mRooms = new prom.Gauge({ name: 'edumeet_rooms', help: '#rooms', registers: [ registry ] });
|
||||
logger.debug('collect');
|
||||
const mRooms = new prom.Gauge({ name: 'edumeet_rooms', help: '#rooms', registers: [ registry ] });
|
||||
|
||||
mRooms.set(rooms.size);
|
||||
const mPeers = new prom.Gauge({ name: 'edumeet_peers', help: '#peers', labelNames: [ 'room_id' ], registers: [ registry ] });
|
||||
mRooms.set(rooms.size);
|
||||
const mPeers = new prom.Gauge({ name: 'edumeet_peers', help: '#peers', labelNames: [ 'room_id' ], registers: [ registry ] });
|
||||
|
||||
for (const [ roomId, room ] of rooms)
|
||||
{
|
||||
mPeers.labels(roomId).set(Object.keys(room._peers).length);
|
||||
}
|
||||
for (const [ roomId, room ] of rooms)
|
||||
{
|
||||
mPeers.labels(roomId).set(Object.keys(room._peers).length);
|
||||
}
|
||||
|
||||
const mConsumer = newMetrics('consumer');
|
||||
const mProducer = newMetrics('producer');
|
||||
const mConsumer = newMetrics('consumer');
|
||||
const mProducer = newMetrics('producer');
|
||||
|
||||
for (const [ pid, worker ] of workers)
|
||||
{
|
||||
logger.debug(`visiting worker ${pid}`);
|
||||
for (const router of worker._routers)
|
||||
{
|
||||
logger.debug(`visiting router ${router.id}`);
|
||||
for (const [ transportId, transport ] of router._transports)
|
||||
{
|
||||
logger.debug(`visiting transport ${transportId}`);
|
||||
const transportJson = await transport.dump();
|
||||
for (const worker of workers)
|
||||
{
|
||||
logger.debug(`visiting worker ${worker.pid}`);
|
||||
for (const router of worker._routers)
|
||||
{
|
||||
logger.debug(`visiting router ${router.id}`);
|
||||
for (const [ transportId, transport ] of router._transports)
|
||||
{
|
||||
logger.debug(`visiting transport ${transportId}`);
|
||||
const transportJson = await transport.dump();
|
||||
|
||||
if (transportJson.iceState != 'completed')
|
||||
{
|
||||
logger.debug(`skipping transport ${transportId}}: ${transportJson.iceState}`);
|
||||
continue;
|
||||
}
|
||||
const iceSelectedTuple = transportJson.iceSelectedTuple;
|
||||
const proto = iceSelectedTuple.protocol;
|
||||
const localAddr = await addr(iceSelectedTuple.localIp,
|
||||
iceSelectedTuple.localPort);
|
||||
const remoteAddr = await addr(iceSelectedTuple.remoteIp,
|
||||
iceSelectedTuple.remotePort);
|
||||
if (transportJson.iceState != 'completed')
|
||||
{
|
||||
logger.debug(`skipping transport ${transportId}}: ${transportJson.iceState}`);
|
||||
continue;
|
||||
}
|
||||
const iceSelectedTuple = transportJson.iceSelectedTuple;
|
||||
const proto = iceSelectedTuple.protocol;
|
||||
const localAddr = await addr(iceSelectedTuple.localIp,
|
||||
iceSelectedTuple.localPort);
|
||||
const remoteAddr = await addr(iceSelectedTuple.remoteIp,
|
||||
iceSelectedTuple.remotePort);
|
||||
|
||||
for (const [ producerId, producer ] of transport._producers)
|
||||
{
|
||||
logger.debug(`visiting producer ${producerId}`);
|
||||
const { roomId, peerId, displayName, userAgent, kind, codec } =
|
||||
for (const [ producerId, producer ] of transport._producers)
|
||||
{
|
||||
logger.debug(`visiting producer ${producerId}`);
|
||||
const { roomId, peerId, displayName, userAgent, kind, codec } =
|
||||
commonLabels(producer, (peer) => peer._producers.has(producerId));
|
||||
const a = await producer.getStats();
|
||||
const a = await producer.getStats();
|
||||
|
||||
for (const x of a)
|
||||
{
|
||||
const type = x.type;
|
||||
const labels = {
|
||||
'pid' : pid,
|
||||
'room_id' : roomId,
|
||||
'peer_id' : peerId,
|
||||
'display_name' : displayName,
|
||||
'user_agent' : userAgent,
|
||||
'transport_id' : quiet(transportId),
|
||||
'proto' : proto,
|
||||
'local_addr' : localAddr,
|
||||
'remote_addr' : remoteAddr,
|
||||
'id' : quiet(producerId),
|
||||
'kind' : kind,
|
||||
'codec' : codec,
|
||||
'type' : type
|
||||
};
|
||||
for (const x of a)
|
||||
{
|
||||
const type = x.type;
|
||||
const labels = {
|
||||
'pid' : worker.pid,
|
||||
'room_id' : roomId,
|
||||
'peer_id' : peerId,
|
||||
'display_name' : displayName,
|
||||
'user_agent' : userAgent,
|
||||
'transport_id' : quiet(transportId),
|
||||
'proto' : proto,
|
||||
'local_addr' : localAddr,
|
||||
'remote_addr' : remoteAddr,
|
||||
'id' : quiet(producerId),
|
||||
'kind' : kind,
|
||||
'codec' : codec,
|
||||
'type' : type
|
||||
};
|
||||
|
||||
for (const [ key, m ] of mProducer)
|
||||
{
|
||||
setValue(key, m, labels, x[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [ consumerId, consumer ] of transport._consumers)
|
||||
{
|
||||
logger.debug(`visiting consumer ${consumerId}`);
|
||||
const { roomId, peerId, displayName, userAgent, kind, codec } =
|
||||
for (const [ key, m ] of mProducer)
|
||||
{
|
||||
setValue(key, m, labels, x[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [ consumerId, consumer ] of transport._consumers)
|
||||
{
|
||||
logger.debug(`visiting consumer ${consumerId}`);
|
||||
const { roomId, peerId, displayName, userAgent, kind, codec } =
|
||||
commonLabels(consumer, (peer) => peer._consumers.has(consumerId));
|
||||
const a = await consumer.getStats();
|
||||
const a = await consumer.getStats();
|
||||
|
||||
for (const x of a)
|
||||
{
|
||||
if (x.type == 'inbound-rtp')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const type = x.type;
|
||||
const labels =
|
||||
{
|
||||
'pid' : pid,
|
||||
'room_id' : roomId,
|
||||
'peer_id' : peerId,
|
||||
'display_name' : displayName,
|
||||
'user_agent' : userAgent,
|
||||
'transport_id' : quiet(transportId),
|
||||
'proto' : proto,
|
||||
'local_addr' : localAddr,
|
||||
'remote_addr' : remoteAddr,
|
||||
'id' : quiet(consumerId),
|
||||
'kind' : kind,
|
||||
'codec' : codec,
|
||||
'type' : type
|
||||
};
|
||||
for (const x of a)
|
||||
{
|
||||
if (x.type == 'inbound-rtp')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const type = x.type;
|
||||
const labels =
|
||||
{
|
||||
'pid' : worker.pid,
|
||||
'room_id' : roomId,
|
||||
'peer_id' : peerId,
|
||||
'display_name' : displayName,
|
||||
'user_agent' : userAgent,
|
||||
'transport_id' : quiet(transportId),
|
||||
'proto' : proto,
|
||||
'local_addr' : localAddr,
|
||||
'remote_addr' : remoteAddr,
|
||||
'id' : quiet(consumerId),
|
||||
'kind' : kind,
|
||||
'codec' : codec,
|
||||
'type' : type
|
||||
};
|
||||
|
||||
for (const [ key, m ] of mConsumer)
|
||||
{
|
||||
setValue(key, m, labels, x[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [ key, m ] of mConsumer)
|
||||
{
|
||||
setValue(key, m, labels, x[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -8,28 +8,18 @@ const collectDefaultMetrics = require('./metrics/default');
|
|||
const RegisterAggregated = require('./metrics/aggregated');
|
||||
|
||||
const logger = new Logger('promClient');
|
||||
const workers = new Map();
|
||||
|
||||
module.exports = async function(rooms, peers, config)
|
||||
import { config } from './config';
|
||||
|
||||
module.exports = async function(workers, rooms, peers)
|
||||
{
|
||||
try
|
||||
{
|
||||
logger.debug(`config.deidentify=${config.deidentify}`);
|
||||
logger.debug(`config.listen=${config.listen}`);
|
||||
logger.debug(`config.numeric=${config.numeric}`);
|
||||
logger.debug(`config.port=${config.port}`);
|
||||
logger.debug(`config.quiet=${config.quiet}`);
|
||||
|
||||
mediasoup.observer.on('newworker', (worker) =>
|
||||
{
|
||||
logger.debug(`observing newworker ${worker.pid} #${workers.size}`);
|
||||
workers.set(worker.pid, worker);
|
||||
worker.observer.on('close', () =>
|
||||
{
|
||||
logger.debug(`observing close worker ${worker.pid} #${workers.size - 1}`);
|
||||
workers.delete(worker.pid);
|
||||
});
|
||||
});
|
||||
logger.debug(`config.prometheus.deidentify=${config.prometheus.deidentify}`);
|
||||
logger.debug(`config.prometheus.listen=${config.prometheus.listen}`);
|
||||
logger.debug(`config.prometheus.numeric=${config.prometheus.numeric}`);
|
||||
logger.debug(`config.prometheus.port=${config.prometheus.port}`);
|
||||
logger.debug(`config.prometheus.quiet=${config.prometheus.quiet}`);
|
||||
|
||||
const app = express();
|
||||
|
||||
|
|
@ -39,7 +29,7 @@ module.exports = async function(rooms, peers, config)
|
|||
logger.debug(`GET ${req.originalUrl}`);
|
||||
const registry = new promClient.Registry();
|
||||
|
||||
await collectDefaultMetrics(workers, rooms, peers, registry, config);
|
||||
await collectDefaultMetrics(workers, rooms, peers, registry, config.prometheus);
|
||||
res.set('Content-Type', registry.contentType);
|
||||
const data = await registry.metrics();
|
||||
|
||||
|
|
@ -47,26 +37,26 @@ module.exports = async function(rooms, peers, config)
|
|||
});
|
||||
|
||||
// aggregated register
|
||||
const registerAggregated = RegisterAggregated(workers, rooms, peers, config);
|
||||
const registerAggregated = RegisterAggregated(workers, rooms, peers, config.prometheus);
|
||||
|
||||
app.get('/metrics', async (req, res) =>
|
||||
{
|
||||
logger.debug(`GET ${req.originalUrl}`);
|
||||
|
||||
if (config.secret && req.headers.authorization !== 'Bearer ' + config.secret)
|
||||
if (config.prometheus.secret && req.headers.authorization !== `Bearer ${ config.prometheus.secret}`)
|
||||
{
|
||||
logger.error(`Invalid authorization header`);
|
||||
logger.error('Invalid authorization header');
|
||||
|
||||
return res.status(401).end();
|
||||
}
|
||||
|
||||
|
||||
res.set('Content-Type', registerAggregated.contentType);
|
||||
const data = await registerAggregated.metrics();
|
||||
|
||||
res.end(data);
|
||||
});
|
||||
|
||||
const server = app.listen(config.port || 8889,
|
||||
config.listen || undefined, () =>
|
||||
const server = app.listen(config.prometheus.port, config.prometheus.listen, () =>
|
||||
{
|
||||
const address = server.address();
|
||||
|
||||
|
|
|
|||
|
|
@ -146,12 +146,6 @@ async function run()
|
|||
// Open the interactive server.
|
||||
await interactiveServer(rooms, peers);
|
||||
|
||||
// start Prometheus exporter
|
||||
if (config.prometheus)
|
||||
{
|
||||
await promExporter(rooms, peers, config.prometheus);
|
||||
}
|
||||
|
||||
if (typeof (config.auth) === 'undefined')
|
||||
{
|
||||
logger.warn('Auth is not configured properly!');
|
||||
|
|
@ -167,6 +161,12 @@ async function run()
|
|||
// Run HTTPS server.
|
||||
await runHttpsServer();
|
||||
|
||||
// start Prometheus exporter
|
||||
if (config.prometheus.enabled)
|
||||
{
|
||||
await promExporter(mediasoupWorkers, rooms, peers);
|
||||
}
|
||||
|
||||
// Run WebSocketServer.
|
||||
await runWebSocketServer();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue