@libp2p/simple-metrics 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +4 -0
- package/README.md +40 -0
- package/dist/index.min.js +3 -0
- package/dist/src/index.d.ts +40 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +182 -0
- package/dist/src/index.js.map +1 -0
- package/package.json +54 -0
- package/src/index.ts +255 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# @libp2p/simple-metrics <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
[](http://libp2p.io/)
|
|
4
|
+
[](https://discuss.libp2p.io)
|
|
5
|
+
[](https://codecov.io/gh/libp2p/js-libp2p-simple-metrics)
|
|
6
|
+
[](https://github.com/libp2p/js-libp2p-simple-metrics/actions/workflows/js-test-and-release.yml?query=branch%3Amain)
|
|
7
|
+
|
|
8
|
+
> Simple in-memory metrics gathering for libp2p
|
|
9
|
+
|
|
10
|
+
## Table of contents <!-- omit in toc -->
|
|
11
|
+
|
|
12
|
+
- [Install](#install)
|
|
13
|
+
- [Browser `<script>` tag](#browser-script-tag)
|
|
14
|
+
- [License](#license)
|
|
15
|
+
- [Contribution](#contribution)
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
$ npm i @libp2p/simple-metrics
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Browser `<script>` tag
|
|
24
|
+
|
|
25
|
+
Loading this module through a script tag will make it's exports available as `Libp2pSimpleMetrics` in the global namespace.
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<script src="https://unpkg.com/@libp2p/simple-metrics/dist/index.min.js"></script>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
Licensed under either of
|
|
34
|
+
|
|
35
|
+
- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / <http://www.apache.org/licenses/LICENSE-2.0>)
|
|
36
|
+
- MIT ([LICENSE-MIT](LICENSE-MIT) / <http://opensource.org/licenses/MIT>)
|
|
37
|
+
|
|
38
|
+
## Contribution
|
|
39
|
+
|
|
40
|
+
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
(function (root, factory) {(typeof module === 'object' && module.exports) ? module.exports = factory() : root.Libp2PSimpleMetrics = factory()}(typeof self !== 'undefined' ? self : this, function () {
|
|
2
|
+
"use strict";var Libp2PSimpleMetrics=(()=>{var ie=Object.create;var j=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var ce=Object.getPrototypeOf,ue=Object.prototype.hasOwnProperty;var D=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),le=(t,e)=>{for(var r in e)j(t,r,{get:e[r],enumerable:!0})},V=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ae(e))!ue.call(t,i)&&i!==r&&j(t,i,{get:()=>e[i],enumerable:!(n=se(e,i))||n.enumerable});return t};var de=(t,e,r)=>(r=t!=null?ie(ce(t)):{},V(e||!t||!t.__esModule?j(r,"default",{value:t,enumerable:!0}):r,t)),fe=t=>V(j({},"__esModule",{value:!0}),t);var X=D((je,_)=>{var U=1e3,k=U*60,R=k*60,E=R*24,pe=E*7,he=E*365.25;_.exports=function(t,e){e=e||{};var r=typeof t;if(r==="string"&&t.length>0)return me(t);if(r==="number"&&isFinite(t))return e.long?Ce(t):be(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))};function me(t){if(t=String(t),!(t.length>100)){var e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(t);if(e){var r=parseFloat(e[1]),n=(e[2]||"ms").toLowerCase();switch(n){case"years":case"year":case"yrs":case"yr":case"y":return r*he;case"weeks":case"week":case"w":return r*pe;case"days":case"day":case"d":return r*E;case"hours":case"hour":case"hrs":case"hr":case"h":return r*R;case"minutes":case"minute":case"mins":case"min":case"m":return r*k;case"seconds":case"second":case"secs":case"sec":case"s":return r*U;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function be(t){var e=Math.abs(t);return e>=E?Math.round(t/E)+"d":e>=R?Math.round(t/R)+"h":e>=k?Math.round(t/k)+"m":e>=U?Math.round(t/U)+"s":t+"ms"}function Ce(t){var e=Math.abs(t);return e>=E?G(t,e,E,"day"):e>=R?G(t,e,R,"hour"):e>=k?G(t,e,k,"minute"):e>=U?G(t,e,U,"second"):t+" ms"}function G(t,e,r,n){var i=e>=r*1.5;return Math.round(t/r)+" "+n+(i?"s":"")}});var K=D((Ge,Z)=>{function ge(t){r.debug=r,r.default=r,r.coerce=g,r.disable=p,r.enable=i,r.enabled=C,r.humanize=X(),r.destroy=I,Object.keys(t).forEach(o=>{r[o]=t[o]}),r.names=[],r.skips=[],r.formatters={};function e(o){let s=0;for(let u=0;u<o.length;u++)s=(s<<5)-s+o.charCodeAt(u),s|=0;return r.colors[Math.abs(s)%r.colors.length]}r.selectColor=e;function r(o){let s,u=null,S,a;function c(...d){if(!c.enabled)return;let f=c,m=Number(new Date),x=m-(s||m);f.diff=x,f.prev=s,f.curr=m,s=m,d[0]=r.coerce(d[0]),typeof d[0]!="string"&&d.unshift("%O");let h=0;d[0]=d[0].replace(/%([a-zA-Z%])/g,(F,w)=>{if(F==="%%")return"%";h++;let M=r.formatters[w];if(typeof M=="function"){let O=d[h];F=M.call(f,O),d.splice(h,1),h--}return F}),r.formatArgs.call(f,d),(f.log||r.log).apply(f,d)}return c.namespace=o,c.useColors=r.useColors(),c.color=r.selectColor(o),c.extend=n,c.destroy=r.destroy,Object.defineProperty(c,"enabled",{enumerable:!0,configurable:!1,get:()=>u!==null?u:(S!==r.namespaces&&(S=r.namespaces,a=r.enabled(o)),a),set:d=>{u=d}}),typeof r.init=="function"&&r.init(c),c}function n(o,s){let u=r(this.namespace+(typeof s>"u"?":":s)+o);return u.log=this.log,u}function i(o){r.save(o),r.namespaces=o,r.names=[],r.skips=[];let s,u=(typeof o=="string"?o:"").split(/[\s,]+/),S=u.length;for(s=0;s<S;s++)u[s]&&(o=u[s].replace(/\*/g,".*?"),o[0]==="-"?r.skips.push(new RegExp("^"+o.slice(1)+"$")):r.names.push(new RegExp("^"+o+"$")))}function p(){let o=[...r.names.map(l),...r.skips.map(l).map(s=>"-"+s)].join(",");return r.enable(""),o}function C(o){if(o[o.length-1]==="*")return!0;let s,u;for(s=0,u=r.skips.length;s<u;s++)if(r.skips[s].test(o))return!1;for(s=0,u=r.names.length;s<u;s++)if(r.names[s].test(o))return!0;return!1}function l(o){return o.toString().substring(2,o.toString().length-2).replace(/\.\*\?$/,"*")}function g(o){return o instanceof Error?o.stack||o.message:o}function I(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return r.enable(r.load()),r}Z.exports=ge});var Q=D((v,P)=>{v.formatArgs=ve;v.save=ye;v.load=xe;v.useColors=we;v.storage=Fe();v.destroy=(()=>{let t=!1;return()=>{t||(t=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();v.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function we(){return typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)?!0:typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)?!1:typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function ve(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+P.exports.humanize(this.diff),!this.useColors)return;let e="color: "+this.color;t.splice(1,0,e,"color: inherit");let r=0,n=0;t[0].replace(/%[a-zA-Z%]/g,i=>{i!=="%%"&&(r++,i==="%c"&&(n=r))}),t.splice(n,0,e)}v.log=console.debug||console.log||(()=>{});function ye(t){try{t?v.storage.setItem("debug",t):v.storage.removeItem("debug")}catch{}}function xe(){let t;try{t=v.storage.getItem("debug")}catch{}return!t&&typeof process<"u"&&"env"in process&&(t=process.env.DEBUG),t}function Fe(){try{return localStorage}catch{}}P.exports=K()(v);var{formatters:Me}=P.exports;Me.j=function(t){try{return JSON.stringify(t)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}});var ze={};le(ze,{simpleMetrics:()=>Ie});var y=de(Q(),1);function Ae(t,e){if(t.length>=255)throw new TypeError("Alphabet too long");for(var r=new Uint8Array(256),n=0;n<r.length;n++)r[n]=255;for(var i=0;i<t.length;i++){var p=t.charAt(i),C=p.charCodeAt(0);if(r[C]!==255)throw new TypeError(p+" is ambiguous");r[C]=i}var l=t.length,g=t.charAt(0),I=Math.log(l)/Math.log(256),o=Math.log(256)/Math.log(l);function s(a){if(a instanceof Uint8Array||(ArrayBuffer.isView(a)?a=new Uint8Array(a.buffer,a.byteOffset,a.byteLength):Array.isArray(a)&&(a=Uint8Array.from(a))),!(a instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(a.length===0)return"";for(var c=0,d=0,f=0,m=a.length;f!==m&&a[f]===0;)f++,c++;for(var x=(m-f)*o+1>>>0,h=new Uint8Array(x);f!==m;){for(var A=a[f],F=0,w=x-1;(A!==0||F<d)&&w!==-1;w--,F++)A+=256*h[w]>>>0,h[w]=A%l>>>0,A=A/l>>>0;if(A!==0)throw new Error("Non-zero carry");d=F,f++}for(var M=x-d;M!==x&&h[M]===0;)M++;for(var O=g.repeat(c);M<x;++M)O+=t.charAt(h[M]);return O}function u(a){if(typeof a!="string")throw new TypeError("Expected String");if(a.length===0)return new Uint8Array;var c=0;if(a[c]!==" "){for(var d=0,f=0;a[c]===g;)d++,c++;for(var m=(a.length-c)*I+1>>>0,x=new Uint8Array(m);a[c];){var h=r[a.charCodeAt(c)];if(h===255)return;for(var A=0,F=m-1;(h!==0||A<f)&&F!==-1;F--,A++)h+=l*x[F]>>>0,x[F]=h%256>>>0,h=h/256>>>0;if(h!==0)throw new Error("Non-zero carry");f=A,c++}if(a[c]!==" "){for(var w=m-f;w!==m&&x[w]===0;)w++;for(var M=new Uint8Array(d+(m-w)),O=d;w!==m;)M[O++]=x[w++];return M}}}function S(a){var c=u(a);if(c)return c;throw new Error(`Non-${e} character`)}return{encode:s,decodeUnsafe:u,decode:S}}var Ee=Ae,Se=Ee,W=Se;var De=new Uint8Array(0);var Y=t=>{if(t instanceof Uint8Array&&t.constructor.name==="Uint8Array")return t;if(t instanceof ArrayBuffer)return new Uint8Array(t);if(ArrayBuffer.isView(t))return new Uint8Array(t.buffer,t.byteOffset,t.byteLength);throw new Error("Unknown type, must be binary type")};var T=class{constructor(e,r,n){this.name=e,this.prefix=r,this.baseEncode=n}encode(e){if(e instanceof Uint8Array)return`${this.prefix}${this.baseEncode(e)}`;throw Error("Unknown type, must be binary type")}},q=class{constructor(e,r,n){if(this.name=e,this.prefix=r,r.codePointAt(0)===void 0)throw new Error("Invalid prefix character");this.prefixCodePoint=r.codePointAt(0),this.baseDecode=n}decode(e){if(typeof e=="string"){if(e.codePointAt(0)!==this.prefixCodePoint)throw Error(`Unable to decode multibase string ${JSON.stringify(e)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);return this.baseDecode(e.slice(this.prefix.length))}else throw Error("Can only multibase decode strings")}or(e){return H(this,e)}},$=class{constructor(e){this.decoders=e}or(e){return H(this,e)}decode(e){let r=e[0],n=this.decoders[r];if(n)return n.decode(e);throw RangeError(`Unable to decode multibase string ${JSON.stringify(e)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`)}},H=(t,e)=>new $({...t.decoders||{[t.prefix]:t},...e.decoders||{[e.prefix]:e}}),L=class{constructor(e,r,n,i){this.name=e,this.prefix=r,this.baseEncode=n,this.baseDecode=i,this.encoder=new T(e,r,n),this.decoder=new q(e,r,i)}encode(e){return this.encoder.encode(e)}decode(e){return this.decoder.decode(e)}},ee=({name:t,prefix:e,encode:r,decode:n})=>new L(t,e,r,n),B=({prefix:t,name:e,alphabet:r})=>{let{encode:n,decode:i}=W(r,e);return ee({prefix:t,name:e,encode:n,decode:p=>Y(i(p))})},Oe=(t,e,r,n)=>{let i={};for(let o=0;o<e.length;++o)i[e[o]]=o;let p=t.length;for(;t[p-1]==="=";)--p;let C=new Uint8Array(p*r/8|0),l=0,g=0,I=0;for(let o=0;o<p;++o){let s=i[t[o]];if(s===void 0)throw new SyntaxError(`Non-${n} character`);g=g<<r|s,l+=r,l>=8&&(l-=8,C[I++]=255&g>>l)}if(l>=r||255&g<<8-l)throw new SyntaxError("Unexpected end of data");return C},Ue=(t,e,r)=>{let n=e[e.length-1]==="=",i=(1<<r)-1,p="",C=0,l=0;for(let g=0;g<t.length;++g)for(l=l<<8|t[g],C+=8;C>r;)C-=r,p+=e[i&l>>C];if(C&&(p+=e[i&l<<r-C]),n)for(;p.length*r&7;)p+="=";return p},b=({name:t,prefix:e,bitsPerChar:r,alphabet:n})=>ee({prefix:e,name:t,encode(i){return Ue(i,n,r)},decode(i){return Oe(i,n,r,t)}});var re=b({prefix:"b",name:"base32",alphabet:"abcdefghijklmnopqrstuvwxyz234567",bitsPerChar:5}),Je=b({prefix:"B",name:"base32upper",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",bitsPerChar:5}),Ve=b({prefix:"c",name:"base32pad",alphabet:"abcdefghijklmnopqrstuvwxyz234567=",bitsPerChar:5}),_e=b({prefix:"C",name:"base32padupper",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",bitsPerChar:5}),Xe=b({prefix:"v",name:"base32hex",alphabet:"0123456789abcdefghijklmnopqrstuv",bitsPerChar:5}),Ze=b({prefix:"V",name:"base32hexupper",alphabet:"0123456789ABCDEFGHIJKLMNOPQRSTUV",bitsPerChar:5}),Ke=b({prefix:"t",name:"base32hexpad",alphabet:"0123456789abcdefghijklmnopqrstuv=",bitsPerChar:5}),Qe=b({prefix:"T",name:"base32hexpadupper",alphabet:"0123456789ABCDEFGHIJKLMNOPQRSTUV=",bitsPerChar:5}),We=b({prefix:"h",name:"base32z",alphabet:"ybndrfg8ejkmcpqxot1uwisza345h769",bitsPerChar:5});var te=B({name:"base58btc",prefix:"z",alphabet:"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"}),er=B({name:"base58flickr",prefix:"Z",alphabet:"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"});var ne=b({prefix:"m",name:"base64",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",bitsPerChar:6}),nr=b({prefix:"M",name:"base64pad",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",bitsPerChar:6}),or=b({prefix:"u",name:"base64url",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",bitsPerChar:6}),ir=b({prefix:"U",name:"base64urlpad",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",bitsPerChar:6});y.default.formatters.b=t=>t==null?"undefined":te.baseEncode(t);y.default.formatters.t=t=>t==null?"undefined":re.baseEncode(t);y.default.formatters.m=t=>t==null?"undefined":ne.baseEncode(t);y.default.formatters.p=t=>t==null?"undefined":t.toString();y.default.formatters.c=t=>t==null?"undefined":t.toString();y.default.formatters.k=t=>t==null?"undefined":t.toString();y.default.formatters.a=t=>t==null?"undefined":t.toString();function ke(t){let e=()=>{};return e.enabled=!1,e.color="",e.diff=0,e.log=()=>{},e.namespace=t,e.destroy=()=>!0,e.extend=()=>e,e}function oe(t){let e=ke(`${t}:trace`);return y.default.enabled(`${t}:trace`)&&y.default.names.map(r=>r.toString()).find(r=>r.includes(":trace"))!=null&&(e=(0,y.default)(`${t}:trace`)),Object.assign((0,y.default)(t),{error:(0,y.default)(`${t}:error`),trace:e})}var Re=oe("libp2p:simple-metrics"),z=class{value=0;update(e){this.value=e}increment(e=1){this.value+=e}decrement(e=1){this.value-=e}reset(){this.value=0}timer(){let e=Date.now();return()=>{this.value=Date.now()-e}}},N=class{values={};update(e){Object.entries(e).forEach(([r,n])=>{this.values[r]=n})}increment(e){Object.entries(e).forEach(([r,n])=>{this.values[r]=this.values[r]??0;let i=typeof n=="number"?n:1;this.values[r]+=Number(i)})}decrement(e){Object.entries(e).forEach(([r,n])=>{this.values[r]=this.values[r]??0;let i=typeof n=="number"?n:1;this.values[r]-=Number(i)})}reset(){this.values={}}timer(e){let r=Date.now();return()=>{this.values[e]=Date.now()-r}}},J=class{metrics=new Map;started;interval;intervalMs;onMetrics;constructor(e,r){this.started=!1,this._emitMetrics=this._emitMetrics.bind(this),this.intervalMs=r.intervalMs??1e3,this.onMetrics=r.onMetrics}isStarted(){return this.started}start(){this.started=!0,this.interval=setInterval(this._emitMetrics,this.intervalMs)}stop(){this.started=!1,clearInterval(this.interval)}_emitMetrics(){Promise.resolve().then(async()=>{let e={};for(let[r,n]of this.metrics.entries())n instanceof z?e[r]=n.value:n instanceof N?e[r]=n.values:e[r]=await n();this.onMetrics(e)}).catch(e=>{Re.error("could not invoke onMetrics callback",e)})}trackMultiaddrConnection(e){}trackProtocolStream(e,r){}registerMetric(e,r={}){if(e==null)throw new Error("Metric name is required");if(r?.calculate!=null){this.metrics.set(e,r.calculate);return}let n=new z;return this.metrics.set(e,n),n}registerMetricGroup(e,r={}){if(e==null)throw new Error("Metric name is required");if(r?.calculate!=null){this.metrics.set(e,r.calculate);return}let n=new z;return this.metrics.set(e,n),n}registerCounter(e,r={}){if(e==null)throw new Error("Metric name is required");if(r?.calculate!=null){this.metrics.set(e,r.calculate);return}let n=new N;return this.metrics.set(e,n),n}registerCounterGroup(e,r={}){if(e==null)throw new Error("Metric name is required");if(r?.calculate!=null){this.metrics.set(e,r.calculate);return}let n=new N;return this.metrics.set(e,n),n}};function Ie(t){return e=>new J(e,t)}return fe(ze);})();
|
|
3
|
+
return Libp2PSimpleMetrics}));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* Stores metrics in memory and periodically invokes a configured callback
|
|
5
|
+
* to receive them.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createLibp2p } from 'libp2p'
|
|
11
|
+
* import { simpleMetrics } from '@libp2p/simple-metrics'
|
|
12
|
+
*
|
|
13
|
+
* const node = await createLibp2p({
|
|
14
|
+
* // ... other options
|
|
15
|
+
* metrics: simpleMetrics({
|
|
16
|
+
* onMetrics: (metrics) => {
|
|
17
|
+
* // do something with metrics
|
|
18
|
+
* }
|
|
19
|
+
* }),
|
|
20
|
+
* intervalMs: 1000 // default 1s
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import type { Metrics } from '@libp2p/interface/metrics';
|
|
26
|
+
export interface OnMetrics {
|
|
27
|
+
(metrics: Record<string, any>): void;
|
|
28
|
+
}
|
|
29
|
+
export interface SimpleMetricsInit {
|
|
30
|
+
/**
|
|
31
|
+
* How often to invoke the onMetrics callback
|
|
32
|
+
*/
|
|
33
|
+
intervalMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* A callback periodically invoked with collected metrics
|
|
36
|
+
*/
|
|
37
|
+
onMetrics: OnMetrics;
|
|
38
|
+
}
|
|
39
|
+
export declare function simpleMetrics(init: SimpleMetricsInit): (components: unknown) => Metrics;
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAkC,OAAO,EAAkF,MAAM,2BAA2B,CAAA;AAwExK,MAAM,WAAW,SAAS;IAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;CAAE;AAEnE,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;OAEG;IACH,SAAS,EAAE,SAAS,CAAA;CACrB;AA4ID,wBAAgB,aAAa,CAAE,IAAI,EAAE,iBAAiB,GAAG,CAAC,UAAU,EAAE,OAAO,KAAK,OAAO,CAExF"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* Stores metrics in memory and periodically invokes a configured callback
|
|
5
|
+
* to receive them.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createLibp2p } from 'libp2p'
|
|
11
|
+
* import { simpleMetrics } from '@libp2p/simple-metrics'
|
|
12
|
+
*
|
|
13
|
+
* const node = await createLibp2p({
|
|
14
|
+
* // ... other options
|
|
15
|
+
* metrics: simpleMetrics({
|
|
16
|
+
* onMetrics: (metrics) => {
|
|
17
|
+
* // do something with metrics
|
|
18
|
+
* }
|
|
19
|
+
* }),
|
|
20
|
+
* intervalMs: 1000 // default 1s
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import { logger } from '@libp2p/logger';
|
|
26
|
+
const log = logger('libp2p:simple-metrics');
|
|
27
|
+
class DefaultMetric {
|
|
28
|
+
value = 0;
|
|
29
|
+
update(value) {
|
|
30
|
+
this.value = value;
|
|
31
|
+
}
|
|
32
|
+
increment(value = 1) {
|
|
33
|
+
this.value += value;
|
|
34
|
+
}
|
|
35
|
+
decrement(value = 1) {
|
|
36
|
+
this.value -= value;
|
|
37
|
+
}
|
|
38
|
+
reset() {
|
|
39
|
+
this.value = 0;
|
|
40
|
+
}
|
|
41
|
+
timer() {
|
|
42
|
+
const start = Date.now();
|
|
43
|
+
return () => {
|
|
44
|
+
this.value = Date.now() - start;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class DefaultGroupMetric {
|
|
49
|
+
values = {};
|
|
50
|
+
update(values) {
|
|
51
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
52
|
+
this.values[key] = value;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
increment(values) {
|
|
56
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
57
|
+
this.values[key] = this.values[key] ?? 0;
|
|
58
|
+
const inc = typeof value === 'number' ? value : 1;
|
|
59
|
+
this.values[key] += Number(inc);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
decrement(values) {
|
|
63
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
64
|
+
this.values[key] = this.values[key] ?? 0;
|
|
65
|
+
const dec = typeof value === 'number' ? value : 1;
|
|
66
|
+
this.values[key] -= Number(dec);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
reset() {
|
|
70
|
+
this.values = {};
|
|
71
|
+
}
|
|
72
|
+
timer(key) {
|
|
73
|
+
const start = Date.now();
|
|
74
|
+
return () => {
|
|
75
|
+
this.values[key] = Date.now() - start;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
class SimpleMetrics {
|
|
80
|
+
metrics = new Map();
|
|
81
|
+
started;
|
|
82
|
+
interval;
|
|
83
|
+
intervalMs;
|
|
84
|
+
onMetrics;
|
|
85
|
+
constructor(components, init) {
|
|
86
|
+
this.started = false;
|
|
87
|
+
this._emitMetrics = this._emitMetrics.bind(this);
|
|
88
|
+
this.intervalMs = init.intervalMs ?? 1000;
|
|
89
|
+
this.onMetrics = init.onMetrics;
|
|
90
|
+
}
|
|
91
|
+
isStarted() {
|
|
92
|
+
return this.started;
|
|
93
|
+
}
|
|
94
|
+
start() {
|
|
95
|
+
this.started = true;
|
|
96
|
+
this.interval = setInterval(this._emitMetrics, this.intervalMs);
|
|
97
|
+
}
|
|
98
|
+
stop() {
|
|
99
|
+
this.started = false;
|
|
100
|
+
clearInterval(this.interval);
|
|
101
|
+
}
|
|
102
|
+
_emitMetrics() {
|
|
103
|
+
void Promise.resolve().then(async () => {
|
|
104
|
+
const output = {};
|
|
105
|
+
for (const [name, metric] of this.metrics.entries()) {
|
|
106
|
+
if (metric instanceof DefaultMetric) {
|
|
107
|
+
output[name] = metric.value;
|
|
108
|
+
}
|
|
109
|
+
else if (metric instanceof DefaultGroupMetric) {
|
|
110
|
+
output[name] = metric.values;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
output[name] = await metric();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
this.onMetrics(output);
|
|
117
|
+
})
|
|
118
|
+
.catch(err => {
|
|
119
|
+
log.error('could not invoke onMetrics callback', err);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
trackMultiaddrConnection(maConn) {
|
|
123
|
+
}
|
|
124
|
+
trackProtocolStream(stream, connection) {
|
|
125
|
+
}
|
|
126
|
+
registerMetric(name, opts = {}) {
|
|
127
|
+
if (name == null ?? name.trim() === '') {
|
|
128
|
+
throw new Error('Metric name is required');
|
|
129
|
+
}
|
|
130
|
+
if (opts?.calculate != null) {
|
|
131
|
+
// calculated metric
|
|
132
|
+
this.metrics.set(name, opts.calculate);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const metric = new DefaultMetric();
|
|
136
|
+
this.metrics.set(name, metric);
|
|
137
|
+
return metric;
|
|
138
|
+
}
|
|
139
|
+
registerMetricGroup(name, opts = {}) {
|
|
140
|
+
if (name == null ?? name.trim() === '') {
|
|
141
|
+
throw new Error('Metric name is required');
|
|
142
|
+
}
|
|
143
|
+
if (opts?.calculate != null) {
|
|
144
|
+
// calculated metric
|
|
145
|
+
this.metrics.set(name, opts.calculate);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const metric = new DefaultMetric();
|
|
149
|
+
this.metrics.set(name, metric);
|
|
150
|
+
return metric;
|
|
151
|
+
}
|
|
152
|
+
registerCounter(name, opts = {}) {
|
|
153
|
+
if (name == null ?? name.trim() === '') {
|
|
154
|
+
throw new Error('Metric name is required');
|
|
155
|
+
}
|
|
156
|
+
if (opts?.calculate != null) {
|
|
157
|
+
// calculated metric
|
|
158
|
+
this.metrics.set(name, opts.calculate);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const metric = new DefaultGroupMetric();
|
|
162
|
+
this.metrics.set(name, metric);
|
|
163
|
+
return metric;
|
|
164
|
+
}
|
|
165
|
+
registerCounterGroup(name, opts = {}) {
|
|
166
|
+
if (name == null ?? name.trim() === '') {
|
|
167
|
+
throw new Error('Metric name is required');
|
|
168
|
+
}
|
|
169
|
+
if (opts?.calculate != null) {
|
|
170
|
+
// calculated metric
|
|
171
|
+
this.metrics.set(name, opts.calculate);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const metric = new DefaultGroupMetric();
|
|
175
|
+
this.metrics.set(name, metric);
|
|
176
|
+
return metric;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export function simpleMetrics(init) {
|
|
180
|
+
return (components) => new SimpleMetrics(components, init);
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@libp2p/simple-metrics",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Simple in-memory metrics gathering for libp2p",
|
|
5
|
+
"license": "Apache-2.0 OR MIT",
|
|
6
|
+
"homepage": "https://github.com/libp2p/js-libp2p-simple-metrics#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/libp2p/js-libp2p-simple-metrics.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/libp2p/js-libp2p-simple-metrics/issues"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"types": "./dist/src/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"src",
|
|
18
|
+
"dist",
|
|
19
|
+
"!dist/test",
|
|
20
|
+
"!**/*.tsbuildinfo"
|
|
21
|
+
],
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/src/index.d.ts",
|
|
25
|
+
"import": "./dist/src/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"eslintConfig": {
|
|
29
|
+
"extends": "ipfs",
|
|
30
|
+
"parserOptions": {
|
|
31
|
+
"sourceType": "module"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"clean": "aegir clean",
|
|
36
|
+
"lint": "aegir lint",
|
|
37
|
+
"build": "aegir build",
|
|
38
|
+
"test": "aegir test",
|
|
39
|
+
"test:node": "aegir test -t node --cov",
|
|
40
|
+
"test:chrome": "aegir test -t browser --cov",
|
|
41
|
+
"test:chrome-webworker": "aegir test -t webworker",
|
|
42
|
+
"test:firefox": "aegir test -t browser -- --browser firefox",
|
|
43
|
+
"test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
|
|
44
|
+
"dep-check": "aegir dep-check -i events"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@libp2p/interface": "^0.1.2",
|
|
48
|
+
"@libp2p/logger": "^3.0.2"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"aegir": "^40.0.13",
|
|
52
|
+
"p-defer": "^4.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* Stores metrics in memory and periodically invokes a configured callback
|
|
5
|
+
* to receive them.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createLibp2p } from 'libp2p'
|
|
11
|
+
* import { simpleMetrics } from '@libp2p/simple-metrics'
|
|
12
|
+
*
|
|
13
|
+
* const node = await createLibp2p({
|
|
14
|
+
* // ... other options
|
|
15
|
+
* metrics: simpleMetrics({
|
|
16
|
+
* onMetrics: (metrics) => {
|
|
17
|
+
* // do something with metrics
|
|
18
|
+
* }
|
|
19
|
+
* }),
|
|
20
|
+
* intervalMs: 1000 // default 1s
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { logger } from '@libp2p/logger'
|
|
27
|
+
import type { MultiaddrConnection, Stream, Connection } from '@libp2p/interface/connection'
|
|
28
|
+
import type { Startable } from '@libp2p/interface/dist/src/startable'
|
|
29
|
+
import type { Metric, MetricGroup, StopTimer, Metrics, CalculatedMetricOptions, MetricOptions, Counter, CounterGroup, CalculateMetric } from '@libp2p/interface/metrics'
|
|
30
|
+
|
|
31
|
+
const log = logger('libp2p:simple-metrics')
|
|
32
|
+
|
|
33
|
+
class DefaultMetric implements Metric {
|
|
34
|
+
public value: number = 0
|
|
35
|
+
|
|
36
|
+
update (value: number): void {
|
|
37
|
+
this.value = value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
increment (value: number = 1): void {
|
|
41
|
+
this.value += value
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
decrement (value: number = 1): void {
|
|
45
|
+
this.value -= value
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
reset (): void {
|
|
49
|
+
this.value = 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
timer (): StopTimer {
|
|
53
|
+
const start = Date.now()
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
this.value = Date.now() - start
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class DefaultGroupMetric implements MetricGroup {
|
|
62
|
+
public values: Record<string, number> = {}
|
|
63
|
+
|
|
64
|
+
update (values: Record<string, number>): void {
|
|
65
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
66
|
+
this.values[key] = value
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
increment (values: Record<string, number | unknown>): void {
|
|
71
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
72
|
+
this.values[key] = this.values[key] ?? 0
|
|
73
|
+
const inc = typeof value === 'number' ? value : 1
|
|
74
|
+
|
|
75
|
+
this.values[key] += Number(inc)
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
decrement (values: Record<string, number | unknown>): void {
|
|
80
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
81
|
+
this.values[key] = this.values[key] ?? 0
|
|
82
|
+
const dec = typeof value === 'number' ? value : 1
|
|
83
|
+
|
|
84
|
+
this.values[key] -= Number(dec)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
reset (): void {
|
|
89
|
+
this.values = {}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
timer (key: string): StopTimer {
|
|
93
|
+
const start = Date.now()
|
|
94
|
+
|
|
95
|
+
return () => {
|
|
96
|
+
this.values[key] = Date.now() - start
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface OnMetrics { (metrics: Record<string, any>): void }
|
|
102
|
+
|
|
103
|
+
export interface SimpleMetricsInit {
|
|
104
|
+
/**
|
|
105
|
+
* How often to invoke the onMetrics callback
|
|
106
|
+
*/
|
|
107
|
+
intervalMs?: number
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* A callback periodically invoked with collected metrics
|
|
111
|
+
*/
|
|
112
|
+
onMetrics: OnMetrics
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
class SimpleMetrics implements Metrics, Startable {
|
|
116
|
+
public metrics = new Map<string, DefaultMetric | DefaultGroupMetric | CalculateMetric>()
|
|
117
|
+
private started: boolean
|
|
118
|
+
private interval?: ReturnType<typeof setInterval>
|
|
119
|
+
private readonly intervalMs: number
|
|
120
|
+
private readonly onMetrics: OnMetrics
|
|
121
|
+
|
|
122
|
+
constructor (components: unknown, init: SimpleMetricsInit) {
|
|
123
|
+
this.started = false
|
|
124
|
+
|
|
125
|
+
this._emitMetrics = this._emitMetrics.bind(this)
|
|
126
|
+
|
|
127
|
+
this.intervalMs = init.intervalMs ?? 1000
|
|
128
|
+
this.onMetrics = init.onMetrics
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
isStarted (): boolean {
|
|
132
|
+
return this.started
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
start (): void {
|
|
136
|
+
this.started = true
|
|
137
|
+
|
|
138
|
+
this.interval = setInterval(this._emitMetrics, this.intervalMs)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
stop (): void {
|
|
142
|
+
this.started = false
|
|
143
|
+
|
|
144
|
+
clearInterval(this.interval)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private _emitMetrics (): void {
|
|
148
|
+
void Promise.resolve().then(async () => {
|
|
149
|
+
const output: Record<string, any> = {}
|
|
150
|
+
|
|
151
|
+
for (const [name, metric] of this.metrics.entries()) {
|
|
152
|
+
if (metric instanceof DefaultMetric) {
|
|
153
|
+
output[name] = metric.value
|
|
154
|
+
} else if (metric instanceof DefaultGroupMetric) {
|
|
155
|
+
output[name] = metric.values
|
|
156
|
+
} else {
|
|
157
|
+
output[name] = await metric()
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.onMetrics(output)
|
|
162
|
+
})
|
|
163
|
+
.catch(err => {
|
|
164
|
+
log.error('could not invoke onMetrics callback', err)
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
trackMultiaddrConnection (maConn: MultiaddrConnection): void {
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
trackProtocolStream (stream: Stream, connection: Connection): void {
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
registerMetric (name: string, opts: CalculatedMetricOptions): void
|
|
177
|
+
registerMetric (name: string, opts?: MetricOptions): Metric
|
|
178
|
+
registerMetric (name: string, opts: any = {}): any {
|
|
179
|
+
if (name == null ?? name.trim() === '') {
|
|
180
|
+
throw new Error('Metric name is required')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (opts?.calculate != null) {
|
|
184
|
+
// calculated metric
|
|
185
|
+
this.metrics.set(name, opts.calculate)
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const metric = new DefaultMetric()
|
|
190
|
+
this.metrics.set(name, metric)
|
|
191
|
+
|
|
192
|
+
return metric
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
registerMetricGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
|
|
196
|
+
registerMetricGroup (name: string, opts?: MetricOptions): MetricGroup
|
|
197
|
+
registerMetricGroup (name: string, opts: any = {}): any {
|
|
198
|
+
if (name == null ?? name.trim() === '') {
|
|
199
|
+
throw new Error('Metric name is required')
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (opts?.calculate != null) {
|
|
203
|
+
// calculated metric
|
|
204
|
+
this.metrics.set(name, opts.calculate)
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const metric = new DefaultMetric()
|
|
209
|
+
this.metrics.set(name, metric)
|
|
210
|
+
|
|
211
|
+
return metric
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
registerCounter (name: string, opts: CalculatedMetricOptions): void
|
|
215
|
+
registerCounter (name: string, opts?: MetricOptions): Counter
|
|
216
|
+
registerCounter (name: string, opts: any = {}): any {
|
|
217
|
+
if (name == null ?? name.trim() === '') {
|
|
218
|
+
throw new Error('Metric name is required')
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (opts?.calculate != null) {
|
|
222
|
+
// calculated metric
|
|
223
|
+
this.metrics.set(name, opts.calculate)
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const metric = new DefaultGroupMetric()
|
|
228
|
+
this.metrics.set(name, metric)
|
|
229
|
+
|
|
230
|
+
return metric
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
registerCounterGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
|
|
234
|
+
registerCounterGroup (name: string, opts?: MetricOptions): CounterGroup
|
|
235
|
+
registerCounterGroup (name: string, opts: any = {}): any {
|
|
236
|
+
if (name == null ?? name.trim() === '') {
|
|
237
|
+
throw new Error('Metric name is required')
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (opts?.calculate != null) {
|
|
241
|
+
// calculated metric
|
|
242
|
+
this.metrics.set(name, opts.calculate)
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const metric = new DefaultGroupMetric()
|
|
247
|
+
this.metrics.set(name, metric)
|
|
248
|
+
|
|
249
|
+
return metric
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function simpleMetrics (init: SimpleMetricsInit): (components: unknown) => Metrics {
|
|
254
|
+
return (components: unknown) => new SimpleMetrics(components, init)
|
|
255
|
+
}
|