Skip to content
This repository was archived by the owner on Jun 26, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 3 additions & 18 deletions packages/interface-metrics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
## Table of contents <!-- omit in toc -->

- [Install](#install)
- [Using the Test Suite](#using-the-test-suite)
- [Implementations](#implementations)
- [License](#license)
- [Contribution](#contribution)

Expand All @@ -21,24 +21,9 @@
$ npm i @libp2p/interface-metrics
```

## Using the Test Suite
## Implementations

You can also check out the [internal test suite](../../test/crypto/compliance.spec.js) to see the setup in action.

```js
const tests = require('libp2p-interfaces-compliance-tests/keys')
const yourKeys = require('./your-keys')

tests({
setup () {
// Set up your keys if needed, then return it
return yourKeys
},
teardown () {
// Clean up your keys if needed
}
})
```
* [@libp2p/prometheus-metrics](https://github.com/libp2p/js-libp2p-prometheus-metrics)

## License

Expand Down
3 changes: 1 addition & 2 deletions packages/interface-metrics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@
"release": "aegir release"
},
"dependencies": {
"@libp2p/interface-peer-id": "^1.0.0",
"it-stream-types": "^1.0.4"
"@libp2p/interface-connection": "^3.0.0"
},
"devDependencies": {
"aegir": "^37.4.0"
Expand Down
232 changes: 111 additions & 121 deletions packages/interface-metrics/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,197 +1,187 @@
import type { PeerId } from '@libp2p/interface-peer-id'
import type { Duplex } from 'it-stream-types'

export interface MetricsInit {
enabled: boolean
computeThrottleMaxQueueSize: number
computeThrottleTimeout: number
movingAverageIntervals: number[]
maxOldPeersRetention: number
}

export interface MovingAverage {
variance: number
movingAverage: number
deviation: number
forecast: number

push: (time: number, value: number) => void
}

export interface MovingAverages {
dataReceived: MovingAverage[]
dataSent: MovingAverage[]
}

export interface TransferStats {
dataReceived: bigint
dataSent: bigint
}
import type { MultiaddrConnection, Stream, Connection } from '@libp2p/interface-connection'

export interface Stats {
/**
* Create tracked metrics with these options. Loosely based on the
* interfaces exposed by the prom-client module
*/
export interface MetricOptions {
/**
* Returns a clone of the current stats.
* Optional label for the metric
*/
getSnapshot: () => TransferStats
label?: string

/**
* Returns a clone of the internal movingAverages
* Optional help for the metric
*/
getMovingAverages: () => MovingAverages
help?: string
}

/**
* A function that returns a tracked metric which may be expensive
* to calculate so it is only invoked when metrics are being scraped
*/
export type CalculateMetric<T = number | bigint> = (() => T) | (() => Promise<T>)

/**
* Create tracked metrics that are expensive to calculate by passing
* a function that is only invoked when metrics are being scraped
*/
export interface CalculatedMetricOptions<T = number | bigint> extends MetricOptions {
/**
* Pushes the given operation data to the queue, along with the
* current Timestamp, then resets the update timer.
* An optional function invoked to calculate the component metric instead of
* using `.update`, `.increment`, and `.decrement`
*/
push: (counter: string, inc: number) => void
calculate: CalculateMetric<T>
}

export interface TrackStreamOptions {
/**
* A duplex iterable stream
*/
stream: Duplex<{ byteLength: number }, any>
/**
* Call this function to stop the timer returned from the `.timer` method
* on the metric
*/
export interface StopTimer { (): void }

/**
* A tracked metric loosely based on the interfaces exposed by the
* prom-client module
*/
export interface Metric {
/**
* The id of the remote peer that's connected
* Update the stored metric to the passed value
*/
remotePeer: PeerId
update: (value: number | bigint) => void

/**
* The protocol the stream is running
* Increment the metric by the passed value or 1
*/
protocol?: string
}
increment: (value?: number | bigint) => void

export interface StreamMetrics {
/**
* Returns the global `Stats` object
* Decrement the metric by the passed value or 1
*/
getGlobal: () => Stats
decrement: (value?: number | bigint) => void

/**
* Returns a list of `PeerId` strings currently being tracked
* Reset this metric to its default value
*/
getPeers: () => string[]
reset: () => void

/**
* Returns the `Stats` object for the given `PeerId` whether it
* is a live peer, or in the disconnected peer LRU cache.
* Start a timed metric, call the returned function to
* stop the timer
*/
forPeer: (peerId: PeerId) => Stats | undefined
timer: () => StopTimer
}

/**
* A group of related metrics loosely based on the interfaces exposed by the
* prom-client module
*/
export interface MetricGroup {
/**
* Returns a list of all protocol strings currently being tracked.
* Update the stored metric group to the passed value
*/
getProtocols: () => string[]
update: (values: Record<string, number | bigint>) => void

/**
* Returns the `Stats` object for the given `protocol`
* Increment the metric group keys by the passed number or
* any non-numeric value to increment by 1
*/
forProtocol: (protocol: string) => Stats | undefined
increment: (values: Record<string, number | bigint | unknown>) => void

/**
* Should be called when all connections to a given peer
* have closed. The `Stats` collection for the peer will
* be stopped and moved to an LRU for temporary retention.
* Decrement the metric group keys by the passed number or
* any non-numeric value to decrement by 1
*/
onPeerDisconnected: (peerId: PeerId) => void
decrement: (values: Record<string, number | bigint | unknown>) => void

/**
* Replaces the `PeerId` string with the given `peerId`.
* If stats are already being tracked for the given `peerId`, the
* placeholder stats will be merged with the existing stats.
* Reset the passed key in this metric group to its default value
* or all keys if no key is passed
*/
updatePlaceholder: (placeholder: PeerId, peerId: PeerId) => void
reset: () => void

/**
* Tracks data running through a given Duplex Iterable `stream`. If
* the `peerId` is not provided, a placeholder string will be created and
* returned. This allows lazy tracking of a peer when the peer is not yet known.
* When the `PeerId` is known, `Metrics.updatePlaceholder` should be called
* with the placeholder string returned from here, and the known `PeerId`.
* Start a timed metric for the named key in the group, call
* the returned function to stop the timer
*/
trackStream: (data: TrackStreamOptions) => void
timer: (key: string) => StopTimer
}

/**
* Used to update a tracked metric. Value can either be a number, an object containing
* key/value pairs or an (optionally async) function to return a number or an object of
* key/value pairs.
* A tracked counter loosely based on the Counter interface exposed
* by the prom-client module - counters are metrics that only go up
*/
export interface ComponentMetricsUpdate {
/**
* Name of the system, e.g. libp2p, ipfs, etc
*/
system: string

/**
* Name of the system component that contains the metric
*/
component: string

export interface Counter {
/**
* Name of the metric being tracked
* Increment the metric by the passed value or 1
*/
metric: string
increment: (value?: number | bigint) => void

/**
* The value or function to calculate the value
* Reset this metric to its default value
*/
value: ComponentMetric | CalculateComponentMetric
reset: () => void
}

/**
* A group of tracked counters loosely based on the Counter interface
* exposed by the prom-client module - counters are metrics that only
* go up
*/
export interface CounterGroup {
/**
* Optional label for the metric
* Increment the metric group keys by the passed number or
* any non-numeric value to increment by 1
*/
label?: string
increment: (values: Record<string, number | bigint | unknown>) => void

/**
* Optional help for the metric
* Reset the passed key in this metric group to its default value
* or all keys if no key is passed
*/
help?: string
reset: () => void
}

export type ComponentMetric = number | ComponentMetricsGroup

/**
* Used to group related metrics together by label and value
* The libp2p metrics tracking object. This interface is only concerned
* with the collection of metrics, please see the individual implementations
* for how to extract metrics for viewing.
*/
export type ComponentMetricsGroup = Record<string, number>

/**
* Used to calculate metric values dynamically
*/
export interface CalculateComponentMetric { (): Promise<ComponentMetric> | ComponentMetric }

export interface TrackedMetric {
export interface Metrics {
/**
* In systems that support them, this label can help make graphs more interpretable
* Track a newly opened multiaddr connection
*/
label?: string
trackMultiaddrConnection: (maConn: MultiaddrConnection) => void

/**
* In systems that support them, this help text can help make graphs more interpretable
* Track a newly opened protocol stream
*/
help?: string
trackProtocolStream: (stream: Stream, connection: Connection) => void

/**
* A function that returns a value or a group of values
* Register an arbitrary metric. Call this to set help/labels for metrics
* and update/increment/decrement/etc them by calling methods on the returned
* metric object
*/
calculate: CalculateComponentMetric
}
registerMetric: ((name: string, options?: MetricOptions) => Metric) & ((name: string, options: CalculatedMetricOptions) => void)

export interface ComponentMetricsTracker {
/**
* Returns tracked metrics key by system, component, metric, value
* Register a a group of related metrics. Call this to set help/labels for
* groups of related metrics that will be updated with by calling `.update`,
* `.increment` and/or `.decrement` methods on the returned metric group object
*/
getComponentMetrics: () => Map<string, Map<string, Map<string, TrackedMetric>>>
registerMetricGroup: ((name: string, options?: MetricOptions) => MetricGroup) & ((name: string, options: CalculatedMetricOptions<Record<string, number | bigint>>) => void)

/**
* Update the stored metric value for the given system and component
* Register an arbitrary counter. Call this to set help/labels for counters
* and increment them by calling methods on the returned counter object
*/
updateComponentMetric: (data: ComponentMetricsUpdate) => void
}

export interface Metrics extends StreamMetrics, ComponentMetricsTracker {
registerCounter: ((name: string, options?: MetricOptions) => Counter) & ((name: string, options: CalculatedMetricOptions) => void)

/**
* Register a a group of related counters. Call this to set help/labels for
* groups of related counters that will be updated with by calling the `.increment`
* method on the returned counter group object
*/
registerCounterGroup: ((name: string, options?: MetricOptions) => CounterGroup) & ((name: string, options: CalculatedMetricOptions<Record<string, number | bigint>>) => void)
}
1 change: 1 addition & 0 deletions packages/interface-mocks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
"@libp2p/interface-connection": "^3.0.0",
"@libp2p/interface-connection-encrypter": "^3.0.0",
"@libp2p/interface-connection-manager": "^1.0.0",
"@libp2p/interface-metrics": "^3.0.0",
"@libp2p/interface-peer-discovery": "^1.0.0",
"@libp2p/interface-peer-id": "^1.0.0",
"@libp2p/interface-peer-info": "^1.0.0",
Expand Down
27 changes: 16 additions & 11 deletions packages/interface-mocks/src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,24 @@ export interface Peer {
registrar: Registrar
}

export function connectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ Connection, Connection ] {
export function multiaddrConnectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ MultiaddrConnection, MultiaddrConnection ] {
const [peerBtoPeerA, peerAtoPeerB] = duplexPair<Uint8Array>()

return [
mockConnection(
mockMultiaddrConnection(peerAtoPeerB, b.peerId), {
registrar: a.registrar
}
),
mockConnection(
mockMultiaddrConnection(peerBtoPeerA, a.peerId), {
registrar: b.registrar
}
)
mockMultiaddrConnection(peerAtoPeerB, b.peerId),
mockMultiaddrConnection(peerBtoPeerA, a.peerId)
]
}

export function connectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ Connection, Connection ] {
const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b)

return [
mockConnection(peerBtoPeerA, {
registrar: a.registrar
}),
mockConnection(peerAtoPeerB, {
registrar: b.registrar
})
]
}
Loading