@prairielearn/opentelemetry 1.5.2 → 1.7.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 +6 -0
- package/README.md +43 -1
- package/dist/index.d.ts +4 -25
- package/dist/index.js +22 -252
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +25 -0
- package/dist/init.js +258 -0
- package/dist/init.js.map +1 -0
- package/dist/metrics.d.ts +8 -0
- package/dist/metrics.js +67 -0
- package/dist/metrics.js.map +1 -0
- package/dist/metrics.test.js +89 -0
- package/dist/metrics.test.js.map +1 -0
- package/dist/tracing.d.ts +2 -0
- package/dist/tracing.js +28 -0
- package/dist/tracing.js.map +1 -0
- package/dist/tracing.test.d.ts +1 -0
- package/dist/{index.test.js → tracing.test.js} +1 -1
- package/dist/tracing.test.js.map +1 -0
- package/package.json +17 -10
- package/src/index.ts +13 -294
- package/src/init.ts +317 -0
- package/src/metrics.test.ts +86 -0
- package/src/metrics.ts +93 -0
- package/src/tracing.ts +25 -0
- package/dist/index.test.js.map +0 -1
- /package/dist/{index.test.d.ts → metrics.test.d.ts} +0 -0
- /package/src/{index.test.ts → tracing.test.ts} +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InMemoryMetricExporter,
|
|
3
|
+
AggregationTemporality,
|
|
4
|
+
MeterProvider,
|
|
5
|
+
PeriodicExportingMetricReader,
|
|
6
|
+
Histogram,
|
|
7
|
+
} from '@opentelemetry/sdk-metrics';
|
|
8
|
+
import { Meter } from '@opentelemetry/api';
|
|
9
|
+
import chai, { assert } from 'chai';
|
|
10
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
11
|
+
|
|
12
|
+
import { instrumentedWithMetrics } from './metrics';
|
|
13
|
+
|
|
14
|
+
chai.use(chaiAsPromised);
|
|
15
|
+
|
|
16
|
+
async function waitForMetricsExport(exporter: InMemoryMetricExporter) {
|
|
17
|
+
while (exporter.getMetrics().length === 0) {
|
|
18
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe('instrumentedWithMetrics', () => {
|
|
23
|
+
let exporter: InMemoryMetricExporter;
|
|
24
|
+
let metricReader: PeriodicExportingMetricReader;
|
|
25
|
+
let meter: Meter;
|
|
26
|
+
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
const meterProvider = new MeterProvider();
|
|
29
|
+
meter = meterProvider.getMeter('test');
|
|
30
|
+
exporter = new InMemoryMetricExporter(AggregationTemporality.DELTA);
|
|
31
|
+
metricReader = new PeriodicExportingMetricReader({
|
|
32
|
+
exporter: exporter,
|
|
33
|
+
exportIntervalMillis: 50,
|
|
34
|
+
});
|
|
35
|
+
meterProvider.addMetricReader(metricReader);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
afterEach(async () => {
|
|
39
|
+
await exporter.shutdown();
|
|
40
|
+
await metricReader.shutdown();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('records a histogram for the function duration', async () => {
|
|
44
|
+
await instrumentedWithMetrics(meter, 'test', async () => {});
|
|
45
|
+
|
|
46
|
+
await waitForMetricsExport(exporter);
|
|
47
|
+
const exportedMetrics = exporter.getMetrics();
|
|
48
|
+
const { scope, metrics } = exportedMetrics[0].scopeMetrics[0];
|
|
49
|
+
const [counterMetric, histogramMetric] = metrics;
|
|
50
|
+
|
|
51
|
+
assert.equal(scope.name, 'test');
|
|
52
|
+
|
|
53
|
+
assert.ok(counterMetric);
|
|
54
|
+
assert.equal(counterMetric.descriptor.name, 'test.error');
|
|
55
|
+
assert.lengthOf(counterMetric.dataPoints, 0);
|
|
56
|
+
|
|
57
|
+
assert.ok(histogramMetric);
|
|
58
|
+
assert.equal(histogramMetric.descriptor.name, 'test.duration');
|
|
59
|
+
assert.equal((histogramMetric.dataPoints[0].value as Histogram).count, 1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('records an error count', async () => {
|
|
63
|
+
await assert.isRejected(
|
|
64
|
+
instrumentedWithMetrics(meter, 'test', async () => {
|
|
65
|
+
throw new Error('error for test');
|
|
66
|
+
}),
|
|
67
|
+
'error for test'
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
await waitForMetricsExport(exporter);
|
|
71
|
+
const exportedMetrics = exporter.getMetrics();
|
|
72
|
+
const { metrics, scope } = exportedMetrics[0].scopeMetrics[0];
|
|
73
|
+
const [counterMetric, histogramMetric] = metrics;
|
|
74
|
+
|
|
75
|
+
assert.ok(scope);
|
|
76
|
+
assert.equal(scope.name, 'test');
|
|
77
|
+
|
|
78
|
+
assert.ok(counterMetric);
|
|
79
|
+
assert.equal(counterMetric.descriptor.name, 'test.error');
|
|
80
|
+
assert.equal(counterMetric.dataPoints[0].value, 1);
|
|
81
|
+
|
|
82
|
+
assert.ok(histogramMetric);
|
|
83
|
+
assert.equal(histogramMetric.descriptor.name, 'test.duration');
|
|
84
|
+
assert.equal((histogramMetric.dataPoints[0].value as Histogram).count, 1);
|
|
85
|
+
});
|
|
86
|
+
});
|
package/src/metrics.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Meter,
|
|
3
|
+
ValueType,
|
|
4
|
+
MetricOptions,
|
|
5
|
+
Histogram,
|
|
6
|
+
Counter,
|
|
7
|
+
UpDownCounter,
|
|
8
|
+
ObservableCounter,
|
|
9
|
+
ObservableUpDownCounter,
|
|
10
|
+
ObservableGauge,
|
|
11
|
+
} from '@opentelemetry/api';
|
|
12
|
+
|
|
13
|
+
const histogramCache = new WeakMap<Meter, Map<string, Histogram>>();
|
|
14
|
+
const counterCache = new WeakMap<Meter, Map<string, Counter>>();
|
|
15
|
+
const upDownCounterCache = new WeakMap<Meter, Map<string, UpDownCounter>>();
|
|
16
|
+
const observableCounterCache = new WeakMap<Meter, Map<string, ObservableCounter>>();
|
|
17
|
+
const observableUpDownCounterCache = new WeakMap<Meter, Map<string, ObservableUpDownCounter>>();
|
|
18
|
+
const observableGaugeCache = new WeakMap<Meter, Map<string, ObservableGauge>>();
|
|
19
|
+
|
|
20
|
+
function getCachedMetric<T>(
|
|
21
|
+
cache: WeakMap<Meter, Map<string, T>>,
|
|
22
|
+
meter: Meter,
|
|
23
|
+
name: string,
|
|
24
|
+
create: () => T
|
|
25
|
+
): T {
|
|
26
|
+
let meterCache = cache.get(meter);
|
|
27
|
+
if (!meterCache) {
|
|
28
|
+
meterCache = new Map();
|
|
29
|
+
cache.set(meter, meterCache);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let metric = meterCache.get(name);
|
|
33
|
+
if (!metric) {
|
|
34
|
+
metric = create();
|
|
35
|
+
meterCache.set(name, metric);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return metric;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getHistogram(meter: Meter, name: string, options?: MetricOptions): Histogram {
|
|
42
|
+
return getCachedMetric(histogramCache, meter, name, () => meter.createHistogram(name, options));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getCounter(meter: Meter, name: string, options?: MetricOptions) {
|
|
46
|
+
return getCachedMetric(counterCache, meter, name, () => meter.createCounter(name, options));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getUpDownCounter(meter: Meter, name: string, options?: MetricOptions) {
|
|
50
|
+
return getCachedMetric(upDownCounterCache, meter, name, () =>
|
|
51
|
+
meter.createUpDownCounter(name, options)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function getObservableCounter(meter: Meter, name: string, options?: MetricOptions) {
|
|
56
|
+
return getCachedMetric(observableCounterCache, meter, name, () =>
|
|
57
|
+
meter.createObservableCounter(name, options)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function getObservableUpDownCounter(meter: Meter, name: string, options?: MetricOptions) {
|
|
62
|
+
return getCachedMetric(observableUpDownCounterCache, meter, name, () =>
|
|
63
|
+
meter.createObservableUpDownCounter(name, options)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getObservableGauge(meter: Meter, name: string, options?: MetricOptions) {
|
|
68
|
+
return getCachedMetric(observableGaugeCache, meter, name, () =>
|
|
69
|
+
meter.createObservableGauge(name, options)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function instrumentedWithMetrics<T>(
|
|
74
|
+
meter: Meter,
|
|
75
|
+
name: string,
|
|
76
|
+
fn: () => Promise<T> | T
|
|
77
|
+
): Promise<T> {
|
|
78
|
+
const error = getCounter(meter, `${name}.error`, { valueType: ValueType.INT });
|
|
79
|
+
const histogram = getHistogram(meter, `${name}.duration`, {
|
|
80
|
+
unit: 'milliseconds',
|
|
81
|
+
valueType: ValueType.DOUBLE,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const start = performance.now();
|
|
85
|
+
try {
|
|
86
|
+
return await fn();
|
|
87
|
+
} catch (e) {
|
|
88
|
+
error.add(1);
|
|
89
|
+
throw e;
|
|
90
|
+
} finally {
|
|
91
|
+
histogram.record(performance.now() - start);
|
|
92
|
+
}
|
|
93
|
+
}
|
package/src/tracing.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Span, SpanStatusCode, trace } from '@opentelemetry/api';
|
|
2
|
+
|
|
3
|
+
export async function instrumented<T>(
|
|
4
|
+
name: string,
|
|
5
|
+
fn: (span: Span) => Promise<T> | T
|
|
6
|
+
): Promise<T> {
|
|
7
|
+
return trace
|
|
8
|
+
.getTracer('default')
|
|
9
|
+
.startActiveSpan<(span: Span) => Promise<T>>(name, async (span) => {
|
|
10
|
+
try {
|
|
11
|
+
const result = await fn(span);
|
|
12
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
13
|
+
return result;
|
|
14
|
+
} catch (e: any) {
|
|
15
|
+
span.setStatus({
|
|
16
|
+
code: SpanStatusCode.ERROR,
|
|
17
|
+
message: e.message,
|
|
18
|
+
});
|
|
19
|
+
span.recordException(e);
|
|
20
|
+
throw e;
|
|
21
|
+
} finally {
|
|
22
|
+
span.end();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
package/dist/index.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
|
|
File without changes
|
|
File without changes
|