From 183f7410f5b92110f957c9a6e9c47ee9b67d3d50 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Fri, 28 Oct 2022 18:01:36 -0500 Subject: [PATCH] Declare metrics locally and use MetricsRegister --- src/index.ts | 10 ++++----- src/listener.ts | 6 ++--- src/metrics.ts | 58 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/index.ts b/src/index.ts index 715cbeb..792843b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,12 +11,10 @@ import { CreateListenerOptions, DialOptions, Listener, symbol, Transport } from import type { AbortOptions, Multiaddr } from '@multiformats/multiaddr' import type { Socket, IpcSocketConnectOpts, TcpSocketConnectOpts } from 'net' import type { Connection } from '@libp2p/interface-connection' -import type { TcpMetrics } from './metrics.js' +import { getMetrics, Metrics, MetricsRegister } from './metrics.js' const log = logger('libp2p:tcp') -export { TcpMetrics } - export interface TCPOptions { /** * An optional number in ms that is used as an inactivity timeout after which the socket will be closed @@ -60,11 +58,11 @@ export interface TCPCreateListenerOptions extends CreateListenerOptions, TCPSock class TCP implements Transport { private readonly opts: TCPOptions - private readonly metrics: TcpMetrics | null + private readonly metrics: Metrics | null - constructor (options: TCPOptions = {}, metrics?: TcpMetrics | null) { + constructor (options: TCPOptions = {}, metricsRegistry?: MetricsRegister | null) { this.opts = options - this.metrics = metrics ?? null + this.metrics = metricsRegistry != null ? getMetrics(metricsRegistry) : null } get [symbol] (): true { diff --git a/src/listener.ts b/src/listener.ts index 5ebdfa2..89b13bd 100644 --- a/src/listener.ts +++ b/src/listener.ts @@ -11,7 +11,7 @@ import type { MultiaddrConnection, Connection } from '@libp2p/interface-connecti import type { Upgrader, Listener, ListenerEvents } from '@libp2p/interface-transport' import type { Multiaddr } from '@multiformats/multiaddr' import type { TCPCreateListenerOptions } from './index.js' -import { ServerStatusMetric, TcpMetrics } from './metrics.js' +import { ServerStatusMetric, Metrics } from './metrics.js' const log = logger('libp2p:tcp:listener') @@ -32,7 +32,7 @@ interface Context extends TCPCreateListenerOptions { socketInactivityTimeout?: number socketCloseTimeout?: number maxConnections?: number - metrics: TcpMetrics | null + metrics: Metrics | null } type Status = {started: false} | {started: true, listeningAddr: Multiaddr, peerId: string | null } @@ -41,7 +41,7 @@ export class TCPListener extends EventEmitter implements Listene private readonly server: net.Server /** Keep track of open connections to destroy in case of timeout */ private readonly connections = new Set() - private readonly metrics: TcpMetrics | null + private readonly metrics: Metrics | null private status: Status = { started: false } diff --git a/src/metrics.ts b/src/metrics.ts index f4754c0..e93b199 100644 --- a/src/metrics.ts +++ b/src/metrics.ts @@ -1,11 +1,53 @@ +export enum ServerStatusMetric { + stopped = 0, + started = 1 +} + +export function getMetrics (register: MetricsRegister) { + return { + serverStatus: register.gauge({ + name: 'libp2p_tcp_server_status', + help: 'Current status of the TCP server' + }), + + connections: register.gauge({ + name: 'libp2p_tcp_connections_count', + help: 'Current active connections in TCP listener' + }), + + listenerErrors: register.gauge<{ error: string }>({ + name: 'libp2p_tcp_listener_errors_total', + help: 'Total count of TCP listener errors by error type', + labelNames: ['error'] + }), + + socketEvents: register.gauge<{ event: string }>({ + name: 'libp2p_tcp_socket_events', + help: 'Total count of TCP socket events by event', + labelNames: ['event'] + }) + } +} + +export type Metrics = ReturnType + /* eslint-disable etc/prefer-interface, @typescript-eslint/method-signature-style */ +export interface MetricsRegister { + gauge(config: GaugeConfig): Gauge +} + +interface GaugeConfig { + name: string + help: string + labelNames?: keyof Labels extends string ? Array : undefined +} + type LabelsGeneric = Record type CollectFn = (metric: Gauge) => void interface Gauge { - // Sorry for this mess, `prom-client` API choices are not great - // If the function signature was `inc(value: number, labels?: Labels)`, this would be simpler + // Follows `prom-client` API choices, to require less middleware on consumer inc(value?: number): void inc(labels: Labels, value?: number): void inc(arg1?: Labels | number, arg2?: number): void @@ -20,15 +62,3 @@ interface Gauge { addCollect(collectFn: CollectFn): void } - -export enum ServerStatusMetric { - stopped = 0, - started = 1 -} - -export interface TcpMetrics { - serverStatus: Gauge - connections: Gauge - listenerErrors: Gauge<{error: string}> - socketEvents: Gauge<{event: string}> -}