@prairielearn/opentelemetry 1.7.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,11 @@
1
1
  # @prairielearn/opentelemetry
2
2
 
3
+ ## 1.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5ae096ba7: Add `createObservableValueGauges()` function
8
+
3
9
  ## 1.7.0
4
10
 
5
11
  ### Minor 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, getCounter, getUpDownCounter, getHistogram, getObservableCounter, getObservableUpDownCounter, getObservableGauge, } 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.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;
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; } });
@@ -22,4 +22,5 @@ Object.defineProperty(exports, "getHistogram", { enumerable: true, get: function
22
22
  Object.defineProperty(exports, "getObservableCounter", { enumerable: true, get: function () { return metrics_1.getObservableCounter; } });
23
23
  Object.defineProperty(exports, "getObservableUpDownCounter", { enumerable: true, get: function () { return metrics_1.getObservableUpDownCounter; } });
24
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; } });
25
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,qCAQmB;AAPjB,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"}
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
@@ -6,3 +6,23 @@ export declare function getObservableCounter(meter: Meter, name: string, options
6
6
  export declare function getObservableUpDownCounter(meter: Meter, name: string, options?: MetricOptions): ObservableUpDownCounter<import("@opentelemetry/api").Attributes>;
7
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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/opentelemetry",
3
- "version": "1.7.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
@@ -11,4 +11,6 @@ export {
11
11
  getObservableCounter,
12
12
  getObservableUpDownCounter,
13
13
  getObservableGauge,
14
+ createObservableValueGauges,
15
+ createObservableValueGaugesOptions,
14
16
  } from './metrics';
package/src/metrics.ts CHANGED
@@ -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
+ }