@prairielearn/opentelemetry 1.6.0 → 1.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @prairielearn/opentelemetry
2
2
 
3
+ ## 1.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5ae096ba7: Add `createObservableValueGauges()` function
8
+
9
+ ## 1.7.0
10
+
11
+ ### Minor Changes
12
+
13
+ - ee0c530b5: Export `getCounter` and all similar functions
14
+
3
15
  ## 1.5.2
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -102,3 +102,20 @@ await instrumentedWithMetrics(meter, 'operation.name', async () => {
102
102
  }
103
103
  });
104
104
  ```
105
+
106
+ To capture statistics about a constantly changing value (for instance, the size of a database connection pool), you can use `createObservableValueGauges`. This will "observe" your chosen value on a regular interval and collect the min/max/average of that value for each metrics collection interval.
107
+
108
+ ```ts
109
+ import { metrics, createObservableValueGauges } from '@prairielearn/opentelemetry';
110
+
111
+ const meter = metrics.getMeter('meter-name');
112
+ createObservableValueGauges(
113
+ meter,
114
+ 'db.pool.size',
115
+ {
116
+ // The interval that your value will be observed, in milliseconds.
117
+ interval: 1000,
118
+ },
119
+ () => pool.size
120
+ );
121
+ ```
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { trace, metrics, context, SpanStatusCode, ValueType } from '@opentelemet
2
2
  export { suppressTracing } from '@opentelemetry/core';
3
3
  export { init, shutdown } from './init';
4
4
  export { instrumented } from './tracing';
5
- export { instrumentedWithMetrics } from './metrics';
5
+ export { instrumentedWithMetrics, getCounter, getUpDownCounter, getHistogram, getObservableCounter, getObservableUpDownCounter, getObservableGauge, createObservableValueGauges, createObservableValueGaugesOptions, } from './metrics';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.instrumentedWithMetrics = exports.instrumented = exports.shutdown = exports.init = exports.suppressTracing = exports.ValueType = exports.SpanStatusCode = exports.context = exports.metrics = exports.trace = void 0;
3
+ exports.createObservableValueGauges = exports.getObservableGauge = exports.getObservableUpDownCounter = exports.getObservableCounter = exports.getHistogram = exports.getUpDownCounter = exports.getCounter = exports.instrumentedWithMetrics = exports.instrumented = exports.shutdown = exports.init = exports.suppressTracing = exports.ValueType = exports.SpanStatusCode = exports.context = exports.metrics = exports.trace = void 0;
4
4
  var api_1 = require("@opentelemetry/api");
5
5
  Object.defineProperty(exports, "trace", { enumerable: true, get: function () { return api_1.trace; } });
6
6
  Object.defineProperty(exports, "metrics", { enumerable: true, get: function () { return api_1.metrics; } });
@@ -16,4 +16,11 @@ var tracing_1 = require("./tracing");
16
16
  Object.defineProperty(exports, "instrumented", { enumerable: true, get: function () { return tracing_1.instrumented; } });
17
17
  var metrics_1 = require("./metrics");
18
18
  Object.defineProperty(exports, "instrumentedWithMetrics", { enumerable: true, get: function () { return metrics_1.instrumentedWithMetrics; } });
19
+ Object.defineProperty(exports, "getCounter", { enumerable: true, get: function () { return metrics_1.getCounter; } });
20
+ Object.defineProperty(exports, "getUpDownCounter", { enumerable: true, get: function () { return metrics_1.getUpDownCounter; } });
21
+ Object.defineProperty(exports, "getHistogram", { enumerable: true, get: function () { return metrics_1.getHistogram; } });
22
+ Object.defineProperty(exports, "getObservableCounter", { enumerable: true, get: function () { return metrics_1.getObservableCounter; } });
23
+ Object.defineProperty(exports, "getObservableUpDownCounter", { enumerable: true, get: function () { return metrics_1.getObservableUpDownCounter; } });
24
+ Object.defineProperty(exports, "getObservableGauge", { enumerable: true, get: function () { return metrics_1.getObservableGauge; } });
25
+ Object.defineProperty(exports, "createObservableValueGauges", { enumerable: true, get: function () { return metrics_1.createObservableValueGauges; } });
19
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,0CAAwF;AAA/E,4FAAA,KAAK,OAAA;AAAE,8FAAA,OAAO,OAAA;AAAE,8FAAA,OAAO,OAAA;AAAE,qGAAA,cAAc,OAAA;AAAE,gGAAA,SAAS,OAAA;AAC3D,4CAAsD;AAA7C,uGAAA,eAAe,OAAA;AAExB,+BAAwC;AAA/B,4FAAA,IAAI,OAAA;AAAE,gGAAA,QAAQ,OAAA;AACvB,qCAAyC;AAAhC,uGAAA,YAAY,OAAA;AACrB,qCAAoD;AAA3C,kHAAA,uBAAuB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,0CAAwF;AAA/E,4FAAA,KAAK,OAAA;AAAE,8FAAA,OAAO,OAAA;AAAE,8FAAA,OAAO,OAAA;AAAE,qGAAA,cAAc,OAAA;AAAE,gGAAA,SAAS,OAAA;AAC3D,4CAAsD;AAA7C,uGAAA,eAAe,OAAA;AAExB,+BAAwC;AAA/B,4FAAA,IAAI,OAAA;AAAE,gGAAA,QAAQ,OAAA;AACvB,qCAAyC;AAAhC,uGAAA,YAAY,OAAA;AACrB,qCAUmB;AATjB,kHAAA,uBAAuB,OAAA;AACvB,qGAAA,UAAU,OAAA;AACV,2GAAA,gBAAgB,OAAA;AAChB,uGAAA,YAAY,OAAA;AACZ,+GAAA,oBAAoB,OAAA;AACpB,qHAAA,0BAA0B,OAAA;AAC1B,6GAAA,kBAAkB,OAAA;AAClB,sHAAA,2BAA2B,OAAA"}
package/dist/metrics.d.ts CHANGED
@@ -1,8 +1,28 @@
1
1
  import { Meter, MetricOptions, Histogram, Counter, UpDownCounter, ObservableCounter, ObservableUpDownCounter, ObservableGauge } from '@opentelemetry/api';
2
- export declare function getHistogram(meter: Meter, name: string, options: MetricOptions): Histogram;
3
- export declare function getCounter(meter: Meter, name: string, options: MetricOptions): Counter<import("@opentelemetry/api").Attributes>;
4
- export declare function getUpDownCounter(meter: Meter, name: string, options: MetricOptions): UpDownCounter<import("@opentelemetry/api").Attributes>;
5
- export declare function getObservableCounter(meter: Meter, name: string, options: MetricOptions): ObservableCounter<import("@opentelemetry/api").Attributes>;
6
- export declare function getObservableUpDownCounter(meter: Meter, name: string, options: MetricOptions): ObservableUpDownCounter<import("@opentelemetry/api").Attributes>;
7
- export declare function getObservableGauge(meter: Meter, name: string, options: MetricOptions): ObservableGauge<import("@opentelemetry/api").Attributes>;
2
+ export declare function getHistogram(meter: Meter, name: string, options?: MetricOptions): Histogram;
3
+ export declare function getCounter(meter: Meter, name: string, options?: MetricOptions): Counter<import("@opentelemetry/api").Attributes>;
4
+ export declare function getUpDownCounter(meter: Meter, name: string, options?: MetricOptions): UpDownCounter<import("@opentelemetry/api").Attributes>;
5
+ export declare function getObservableCounter(meter: Meter, name: string, options?: MetricOptions): ObservableCounter<import("@opentelemetry/api").Attributes>;
6
+ export declare function getObservableUpDownCounter(meter: Meter, name: string, options?: MetricOptions): ObservableUpDownCounter<import("@opentelemetry/api").Attributes>;
7
+ export declare function getObservableGauge(meter: Meter, name: string, options?: MetricOptions): ObservableGauge<import("@opentelemetry/api").Attributes>;
8
8
  export declare function instrumentedWithMetrics<T>(meter: Meter, name: string, fn: () => Promise<T> | T): Promise<T>;
9
+ export interface createObservableValueGaugesOptions extends MetricOptions {
10
+ interval: number;
11
+ }
12
+ /**
13
+ * Creates a set of gauges that track the min, max, and average of a value over
14
+ * time. The value is observed on a regular interval.
15
+ *
16
+ * The provided {@link name} is used as the base name for the three gauges. The
17
+ * names of the individual gauges are:
18
+ *
19
+ * - `${name}.min`
20
+ * - `${name}.max`
21
+ * - `${name}.avg`
22
+ */
23
+ export declare function createObservableValueGauges(meter: Meter, name: string, options: createObservableValueGaugesOptions, observe: () => number): Promise<{
24
+ minGauge: ObservableGauge<import("@opentelemetry/api").Attributes>;
25
+ maxGauge: ObservableGauge<import("@opentelemetry/api").Attributes>;
26
+ averageGauge: ObservableGauge<import("@opentelemetry/api").Attributes>;
27
+ stop: () => void;
28
+ }>;
package/dist/metrics.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.instrumentedWithMetrics = exports.getObservableGauge = exports.getObservableUpDownCounter = exports.getObservableCounter = exports.getUpDownCounter = exports.getCounter = exports.getHistogram = void 0;
3
+ exports.createObservableValueGauges = exports.instrumentedWithMetrics = exports.getObservableGauge = exports.getObservableUpDownCounter = exports.getObservableCounter = exports.getUpDownCounter = exports.getCounter = exports.getHistogram = void 0;
4
4
  const api_1 = require("@opentelemetry/api");
5
5
  const histogramCache = new WeakMap();
6
6
  const counterCache = new WeakMap();
@@ -64,4 +64,58 @@ async function instrumentedWithMetrics(meter, name, fn) {
64
64
  }
65
65
  }
66
66
  exports.instrumentedWithMetrics = instrumentedWithMetrics;
67
+ /**
68
+ * Creates a set of gauges that track the min, max, and average of a value over
69
+ * time. The value is observed on a regular interval.
70
+ *
71
+ * The provided {@link name} is used as the base name for the three gauges. The
72
+ * names of the individual gauges are:
73
+ *
74
+ * - `${name}.min`
75
+ * - `${name}.max`
76
+ * - `${name}.avg`
77
+ */
78
+ async function createObservableValueGauges(meter, name, options, observe) {
79
+ const { interval, ...metricOptions } = options;
80
+ let min = 0;
81
+ let max = 0;
82
+ let sum = 0;
83
+ let count = 0;
84
+ // Observe the value on a regular interval. Black-hole any errors.
85
+ const intervalId = setInterval(() => {
86
+ Promise.resolve(observe())
87
+ .then((value) => {
88
+ min = count == 0 ? value : Math.min(min, value);
89
+ max = Math.max(max, value);
90
+ sum += value;
91
+ count += 1;
92
+ })
93
+ .catch(() => { });
94
+ }, interval);
95
+ // Don't let this keep the process alive.
96
+ intervalId.unref();
97
+ const minGauge = getObservableGauge(meter, `${name}.min`, metricOptions);
98
+ const maxGauge = getObservableGauge(meter, `${name}.max`, metricOptions);
99
+ const averageGauge = getObservableGauge(meter, `${name}.avg`, {
100
+ ...metricOptions,
101
+ // Average is always a double, even if the observed value is an int.
102
+ valueType: api_1.ValueType.DOUBLE,
103
+ });
104
+ minGauge.addCallback((observableResult) => {
105
+ observableResult.observe(min);
106
+ min = 0;
107
+ });
108
+ maxGauge.addCallback((observableResult) => {
109
+ observableResult.observe(max);
110
+ max = 0;
111
+ });
112
+ averageGauge.addCallback((observableResult) => {
113
+ const avg = sum / count;
114
+ observableResult.observe(avg);
115
+ sum = 0;
116
+ count = 0;
117
+ });
118
+ return { minGauge, maxGauge, averageGauge, stop: () => clearInterval(intervalId) };
119
+ }
120
+ exports.createObservableValueGauges = createObservableValueGauges;
67
121
  //# sourceMappingURL=metrics.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":";;;AAAA,4CAU4B;AAE5B,MAAM,cAAc,GAAG,IAAI,OAAO,EAAiC,CAAC;AACpE,MAAM,YAAY,GAAG,IAAI,OAAO,EAA+B,CAAC;AAChE,MAAM,kBAAkB,GAAG,IAAI,OAAO,EAAqC,CAAC;AAC5E,MAAM,sBAAsB,GAAG,IAAI,OAAO,EAAyC,CAAC;AACpF,MAAM,4BAA4B,GAAG,IAAI,OAAO,EAA+C,CAAC;AAChG,MAAM,oBAAoB,GAAG,IAAI,OAAO,EAAuC,CAAC;AAEhF,SAAS,eAAe,CACtB,KAAqC,EACrC,KAAY,EACZ,IAAY,EACZ,MAAe;IAEf,IAAI,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,UAAU,EAAE;QACf,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC;QACvB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;KAC9B;IAED,IAAI,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,GAAG,MAAM,EAAE,CAAC;QAClB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;KAC9B;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,YAAY,CAAC,KAAY,EAAE,IAAY,EAAE,OAAuB;IAC9E,OAAO,eAAe,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAClG,CAAC;AAFD,oCAEC;AAED,SAAgB,UAAU,CAAC,KAAY,EAAE,IAAY,EAAE,OAAuB;IAC5E,OAAO,eAAe,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAC9F,CAAC;AAFD,gCAEC;AAED,SAAgB,gBAAgB,CAAC,KAAY,EAAE,IAAY,EAAE,OAAuB;IAClF,OAAO,eAAe,CAAC,kBAAkB,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAC3D,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CACzC,CAAC;AACJ,CAAC;AAJD,4CAIC;AAED,SAAgB,oBAAoB,CAAC,KAAY,EAAE,IAAY,EAAE,OAAuB;IACtF,OAAO,eAAe,CAAC,sBAAsB,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAC/D,KAAK,CAAC,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,CAC7C,CAAC;AACJ,CAAC;AAJD,oDAIC;AAED,SAAgB,0BAA0B,CAAC,KAAY,EAAE,IAAY,EAAE,OAAuB;IAC5F,OAAO,eAAe,CAAC,4BAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CACrE,KAAK,CAAC,6BAA6B,CAAC,IAAI,EAAE,OAAO,CAAC,CACnD,CAAC;AACJ,CAAC;AAJD,gEAIC;AAED,SAAgB,kBAAkB,CAAC,KAAY,EAAE,IAAY,EAAE,OAAuB;IACpF,OAAO,eAAe,CAAC,oBAAoB,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAC7D,KAAK,CAAC,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAC3C,CAAC;AACJ,CAAC;AAJD,gDAIC;AAEM,KAAK,UAAU,uBAAuB,CAC3C,KAAY,EACZ,IAAY,EACZ,EAAwB;IAExB,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,IAAI,QAAQ,EAAE,EAAE,SAAS,EAAE,eAAS,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,IAAI,WAAW,EAAE;QACxD,IAAI,EAAE,cAAc;QACpB,SAAS,EAAE,eAAS,CAAC,MAAM;KAC5B,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,IAAI;QACF,OAAO,MAAM,EAAE,EAAE,CAAC;KACnB;IAAC,OAAO,CAAC,EAAE;QACV,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACb,MAAM,CAAC,CAAC;KACT;YAAS;QACR,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;KAC7C;AACH,CAAC;AApBD,0DAoBC;AAMD;;;;;;;;;;GAUG;AACI,KAAK,UAAU,2BAA2B,CAC/C,KAAY,EACZ,IAAY,EACZ,OAA2C,EAC3C,OAAqB;IAErB,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IAE/C,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,kEAAkE;IAClE,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;aACvB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YACd,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAChD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3B,GAAG,IAAI,KAAK,CAAC;YACb,KAAK,IAAI,CAAC,CAAC;QACb,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrB,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEb,yCAAyC;IACzC,UAAU,CAAC,KAAK,EAAE,CAAC;IAEnB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,GAAG,IAAI,MAAM,EAAE,aAAa,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,GAAG,IAAI,MAAM,EAAE,aAAa,CAAC,CAAC;IACzE,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,EAAE,GAAG,IAAI,MAAM,EAAE;QAC5D,GAAG,aAAa;QAChB,oEAAoE;QACpE,SAAS,EAAE,eAAS,CAAC,MAAM;KAC5B,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,CAAC,CAAC,gBAAgB,EAAE,EAAE;QACxC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAE9B,GAAG,GAAG,CAAC,CAAC;IACV,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,CAAC,CAAC,gBAAgB,EAAE,EAAE;QACxC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAE9B,GAAG,GAAG,CAAC,CAAC;IACV,CAAC,CAAC,CAAC;IAEH,YAAY,CAAC,WAAW,CAAC,CAAC,gBAAgB,EAAE,EAAE;QAC5C,MAAM,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC;QACxB,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAE9B,GAAG,GAAG,CAAC,CAAC;QACR,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;AACrF,CAAC;AAzDD,kEAyDC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/opentelemetry",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
6
  "build": "tsc",
@@ -8,7 +8,7 @@
8
8
  "test": "mocha --no-config --require ts-node/register src/**/*.test.ts"
9
9
  },
10
10
  "dependencies": {
11
- "@grpc/grpc-js": "^1.8.8",
11
+ "@grpc/grpc-js": "^1.8.11",
12
12
  "@opentelemetry/api": "^1.4.0",
13
13
  "@opentelemetry/core": "^1.9.1",
14
14
  "@opentelemetry/exporter-jaeger": "^1.9.1",
@@ -34,7 +34,7 @@
34
34
  "@prairielearn/tsconfig": "*",
35
35
  "@types/chai": "^4.3.4",
36
36
  "@types/mocha": "^10.0.1",
37
- "@types/node": "^18.11.18",
37
+ "@types/node": "^18.14.2",
38
38
  "chai": "^4.3.7",
39
39
  "mocha": "^10.2.0",
40
40
  "ts-node": "^10.9.1",
package/src/index.ts CHANGED
@@ -3,4 +3,14 @@ export { suppressTracing } from '@opentelemetry/core';
3
3
 
4
4
  export { init, shutdown } from './init';
5
5
  export { instrumented } from './tracing';
6
- export { instrumentedWithMetrics } from './metrics';
6
+ export {
7
+ instrumentedWithMetrics,
8
+ getCounter,
9
+ getUpDownCounter,
10
+ getHistogram,
11
+ getObservableCounter,
12
+ getObservableUpDownCounter,
13
+ getObservableGauge,
14
+ createObservableValueGauges,
15
+ createObservableValueGaugesOptions,
16
+ } from './metrics';
package/src/metrics.ts CHANGED
@@ -38,33 +38,33 @@ function getCachedMetric<T>(
38
38
  return metric;
39
39
  }
40
40
 
41
- export function getHistogram(meter: Meter, name: string, options: MetricOptions): Histogram {
41
+ export function getHistogram(meter: Meter, name: string, options?: MetricOptions): Histogram {
42
42
  return getCachedMetric(histogramCache, meter, name, () => meter.createHistogram(name, options));
43
43
  }
44
44
 
45
- export function getCounter(meter: Meter, name: string, options: MetricOptions) {
45
+ export function getCounter(meter: Meter, name: string, options?: MetricOptions) {
46
46
  return getCachedMetric(counterCache, meter, name, () => meter.createCounter(name, options));
47
47
  }
48
48
 
49
- export function getUpDownCounter(meter: Meter, name: string, options: MetricOptions) {
49
+ export function getUpDownCounter(meter: Meter, name: string, options?: MetricOptions) {
50
50
  return getCachedMetric(upDownCounterCache, meter, name, () =>
51
51
  meter.createUpDownCounter(name, options)
52
52
  );
53
53
  }
54
54
 
55
- export function getObservableCounter(meter: Meter, name: string, options: MetricOptions) {
55
+ export function getObservableCounter(meter: Meter, name: string, options?: MetricOptions) {
56
56
  return getCachedMetric(observableCounterCache, meter, name, () =>
57
57
  meter.createObservableCounter(name, options)
58
58
  );
59
59
  }
60
60
 
61
- export function getObservableUpDownCounter(meter: Meter, name: string, options: MetricOptions) {
61
+ export function getObservableUpDownCounter(meter: Meter, name: string, options?: MetricOptions) {
62
62
  return getCachedMetric(observableUpDownCounterCache, meter, name, () =>
63
63
  meter.createObservableUpDownCounter(name, options)
64
64
  );
65
65
  }
66
66
 
67
- export function getObservableGauge(meter: Meter, name: string, options: MetricOptions) {
67
+ export function getObservableGauge(meter: Meter, name: string, options?: MetricOptions) {
68
68
  return getCachedMetric(observableGaugeCache, meter, name, () =>
69
69
  meter.createObservableGauge(name, options)
70
70
  );
@@ -91,3 +91,77 @@ export async function instrumentedWithMetrics<T>(
91
91
  histogram.record(performance.now() - start);
92
92
  }
93
93
  }
94
+
95
+ export interface createObservableValueGaugesOptions extends MetricOptions {
96
+ interval: number;
97
+ }
98
+
99
+ /**
100
+ * Creates a set of gauges that track the min, max, and average of a value over
101
+ * time. The value is observed on a regular interval.
102
+ *
103
+ * The provided {@link name} is used as the base name for the three gauges. The
104
+ * names of the individual gauges are:
105
+ *
106
+ * - `${name}.min`
107
+ * - `${name}.max`
108
+ * - `${name}.avg`
109
+ */
110
+ export async function createObservableValueGauges(
111
+ meter: Meter,
112
+ name: string,
113
+ options: createObservableValueGaugesOptions,
114
+ observe: () => number
115
+ ) {
116
+ const { interval, ...metricOptions } = options;
117
+
118
+ let min = 0;
119
+ let max = 0;
120
+ let sum = 0;
121
+ let count = 0;
122
+
123
+ // Observe the value on a regular interval. Black-hole any errors.
124
+ const intervalId = setInterval(() => {
125
+ Promise.resolve(observe())
126
+ .then((value) => {
127
+ min = count == 0 ? value : Math.min(min, value);
128
+ max = Math.max(max, value);
129
+ sum += value;
130
+ count += 1;
131
+ })
132
+ .catch(() => {});
133
+ }, interval);
134
+
135
+ // Don't let this keep the process alive.
136
+ intervalId.unref();
137
+
138
+ const minGauge = getObservableGauge(meter, `${name}.min`, metricOptions);
139
+ const maxGauge = getObservableGauge(meter, `${name}.max`, metricOptions);
140
+ const averageGauge = getObservableGauge(meter, `${name}.avg`, {
141
+ ...metricOptions,
142
+ // Average is always a double, even if the observed value is an int.
143
+ valueType: ValueType.DOUBLE,
144
+ });
145
+
146
+ minGauge.addCallback((observableResult) => {
147
+ observableResult.observe(min);
148
+
149
+ min = 0;
150
+ });
151
+
152
+ maxGauge.addCallback((observableResult) => {
153
+ observableResult.observe(max);
154
+
155
+ max = 0;
156
+ });
157
+
158
+ averageGauge.addCallback((observableResult) => {
159
+ const avg = sum / count;
160
+ observableResult.observe(avg);
161
+
162
+ sum = 0;
163
+ count = 0;
164
+ });
165
+
166
+ return { minGauge, maxGauge, averageGauge, stop: () => clearInterval(intervalId) };
167
+ }