metrics.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // @ts-check
  2. import metrics from 'prom-client';
  3. /**
  4. * @typedef StreamingMetrics
  5. * @property {metrics.Registry} register
  6. * @property {metrics.Gauge<"type">} connectedClients
  7. * @property {metrics.Gauge<"type" | "channel">} connectedChannels
  8. * @property {metrics.Gauge} redisSubscriptions
  9. * @property {metrics.Counter} redisMessagesReceived
  10. * @property {metrics.Counter<"type">} messagesSent
  11. */
  12. /**
  13. *
  14. * @param {string[]} channels
  15. * @param {import('pg').Pool} pgPool
  16. * @returns {StreamingMetrics}
  17. */
  18. export function setupMetrics(channels, pgPool) {
  19. // Collect metrics from Node.js
  20. metrics.collectDefaultMetrics();
  21. new metrics.Gauge({
  22. name: 'pg_pool_total_connections',
  23. help: 'The total number of clients existing within the pool',
  24. collect() {
  25. this.set(pgPool.totalCount);
  26. },
  27. });
  28. new metrics.Gauge({
  29. name: 'pg_pool_idle_connections',
  30. help: 'The number of clients which are not checked out but are currently idle in the pool',
  31. collect() {
  32. this.set(pgPool.idleCount);
  33. },
  34. });
  35. new metrics.Gauge({
  36. name: 'pg_pool_waiting_queries',
  37. help: 'The number of queued requests waiting on a client when all clients are checked out',
  38. collect() {
  39. this.set(pgPool.waitingCount);
  40. },
  41. });
  42. const connectedClients = new metrics.Gauge({
  43. name: 'connected_clients',
  44. help: 'The number of clients connected to the streaming server',
  45. labelNames: ['type'],
  46. });
  47. const connectedChannels = new metrics.Gauge({
  48. name: 'connected_channels',
  49. help: 'The number of channels the streaming server is streaming to',
  50. labelNames: [ 'type', 'channel' ]
  51. });
  52. const redisSubscriptions = new metrics.Gauge({
  53. name: 'redis_subscriptions',
  54. help: 'The number of Redis channels the streaming server is subscribed to',
  55. });
  56. const redisMessagesReceived = new metrics.Counter({
  57. name: 'redis_messages_received_total',
  58. help: 'The total number of messages the streaming server has received from redis subscriptions'
  59. });
  60. const messagesSent = new metrics.Counter({
  61. name: 'messages_sent_total',
  62. help: 'The total number of messages the streaming server sent to clients per connection type',
  63. labelNames: [ 'type' ]
  64. });
  65. // Prime the gauges so we don't loose metrics between restarts:
  66. redisSubscriptions.set(0);
  67. connectedClients.set({ type: 'websocket' }, 0);
  68. connectedClients.set({ type: 'eventsource' }, 0);
  69. // For each channel, initialize the gauges at zero; There's only a finite set of channels available
  70. channels.forEach(( channel ) => {
  71. connectedChannels.set({ type: 'websocket', channel }, 0);
  72. connectedChannels.set({ type: 'eventsource', channel }, 0);
  73. });
  74. // Prime the counters so that we don't loose metrics between restarts.
  75. // Unfortunately counters don't support the set() API, so instead I'm using
  76. // inc(0) to achieve the same result.
  77. redisMessagesReceived.inc(0);
  78. messagesSent.inc({ type: 'websocket' }, 0);
  79. messagesSent.inc({ type: 'eventsource' }, 0);
  80. return {
  81. register: metrics.register,
  82. connectedClients,
  83. connectedChannels,
  84. redisSubscriptions,
  85. redisMessagesReceived,
  86. messagesSent,
  87. };
  88. }