@prairielearn/opentelemetry 1.1.0 → 1.4.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +18 -0
- package/README.md +19 -4
- package/dist/index.d.ts +6 -2
- package/dist/index.js +74 -30
- package/dist/index.js.map +1 -1
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +65 -0
- package/dist/index.test.js.map +1 -0
- package/package.json +23 -19
- package/src/index.test.ts +75 -0
- package/src/index.ts +79 -30
- package/tsconfig.json +2 -11
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
@prairielearn/opentelemetry:build: cache hit, replaying output
|
|
1
|
+
@prairielearn/opentelemetry:build: cache hit, replaying output eb2ee28f25a984bf
|
|
2
2
|
@prairielearn/opentelemetry:build: warning package.json: No license field
|
|
3
3
|
@prairielearn/opentelemetry:build: $ tsc
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @prairielearn/opentelemetry
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c9a9286dd: Upgrade OpenTelemetry packages
|
|
8
|
+
|
|
9
|
+
## 1.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 24a37b4b7: Bump OpenTelemetry dependencies to their latest versions
|
|
14
|
+
|
|
15
|
+
## 1.2.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 2ef7a73e8: Add `instrumented()` helper to instrument function calls
|
|
20
|
+
|
|
3
21
|
## 1.1.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -23,13 +23,28 @@ await init({
|
|
|
23
23
|
|
|
24
24
|
This will automatically instrument a variety of commonly-used Node packages.
|
|
25
25
|
|
|
26
|
-
To
|
|
26
|
+
To easily instrument individual pieces of functionality, you can use the `instrumented()` helper function:
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
|
-
import {
|
|
29
|
+
import { instrumented } from '@prairielearn/opentelemetry';
|
|
30
|
+
|
|
31
|
+
async function doThing() {
|
|
32
|
+
return instrumented('span.name', async (span) => {
|
|
33
|
+
span.setAttribute('attribute.name', 'value');
|
|
34
|
+
await doThing();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This will automatically set the span status and record any exceptions that occur.
|
|
40
|
+
|
|
41
|
+
If you have a more complex use case, you can manually instrument code with the `trace` export:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { trace, SpanStatusCode } from '@prairielearn/opentelemetry';
|
|
30
45
|
|
|
31
|
-
const tracer = trace.getTracer('
|
|
32
|
-
await tracer.startActiveSpan('span
|
|
46
|
+
const tracer = trace.getTracer('default');
|
|
47
|
+
await tracer.startActiveSpan('span.name', async (span) => {
|
|
33
48
|
try {
|
|
34
49
|
await doWork();
|
|
35
50
|
span.setStatus({ status: SpanStatusCode.OK });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { SpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
2
|
+
import { Span } from '@opentelemetry/api';
|
|
1
3
|
export interface OpenTelemetryConfig {
|
|
2
4
|
openTelemetryEnabled: boolean;
|
|
3
|
-
openTelemetryExporter
|
|
4
|
-
openTelemetrySamplerType
|
|
5
|
+
openTelemetryExporter: 'console' | 'honeycomb' | SpanExporter;
|
|
6
|
+
openTelemetrySamplerType: 'always-on' | 'always-off' | 'trace-id-ratio';
|
|
5
7
|
openTelemetrySampleRate?: number;
|
|
8
|
+
openTelemetrySpanProcessor?: 'batch' | 'simple';
|
|
6
9
|
honeycombApiKey?: string;
|
|
7
10
|
honeycombDataset?: string;
|
|
8
11
|
serviceName?: string;
|
|
@@ -18,5 +21,6 @@ export declare function init(config: OpenTelemetryConfig): Promise<void>;
|
|
|
18
21
|
* when a `SIGTERM` signal is handled.
|
|
19
22
|
*/
|
|
20
23
|
export declare function shutdown(): Promise<void>;
|
|
24
|
+
export declare function instrumented<T>(name: string, fn: (span: Span) => Promise<T> | T): Promise<T>;
|
|
21
25
|
export { trace, context, SpanStatusCode } from '@opentelemetry/api';
|
|
22
26
|
export { suppressTracing } from '@opentelemetry/core';
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.suppressTracing = exports.SpanStatusCode = exports.context = exports.trace = exports.shutdown = exports.init = void 0;
|
|
3
|
+
exports.suppressTracing = exports.SpanStatusCode = exports.context = exports.trace = exports.instrumented = exports.shutdown = exports.init = void 0;
|
|
4
4
|
const grpc_js_1 = require("@grpc/grpc-js");
|
|
5
5
|
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
6
6
|
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
|
|
7
|
+
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
7
8
|
const resources_1 = require("@opentelemetry/resources");
|
|
8
9
|
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
9
10
|
const exporter_otlp_grpc_1 = require("@opentelemetry/exporter-otlp-grpc");
|
|
10
11
|
const instrumentation_express_1 = require("@opentelemetry/instrumentation-express");
|
|
11
|
-
const
|
|
12
|
+
const sdk_trace_base_2 = require("@opentelemetry/sdk-trace-base");
|
|
13
|
+
const api_1 = require("@opentelemetry/api");
|
|
12
14
|
const core_1 = require("@opentelemetry/core");
|
|
13
15
|
// Instrumentations go here.
|
|
14
16
|
const instrumentation_aws_sdk_1 = require("@opentelemetry/instrumentation-aws-sdk");
|
|
@@ -26,7 +28,7 @@ const resources_2 = require("@opentelemetry/resources");
|
|
|
26
28
|
* before they're queued up to send. This enhances our samping process so
|
|
27
29
|
* that we can filter spans _after_ they've been emitted.
|
|
28
30
|
*/
|
|
29
|
-
class FilterBatchSpanProcessor extends
|
|
31
|
+
class FilterBatchSpanProcessor extends sdk_trace_base_2.BatchSpanProcessor {
|
|
30
32
|
constructor(exporter, filter) {
|
|
31
33
|
super(exporter);
|
|
32
34
|
this.filter = filter;
|
|
@@ -111,30 +113,35 @@ async function init(config) {
|
|
|
111
113
|
return;
|
|
112
114
|
}
|
|
113
115
|
let exporter;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
metadata,
|
|
130
|
-
|
|
131
|
-
|
|
116
|
+
if (typeof config.openTelemetryExporter === 'object') {
|
|
117
|
+
exporter = config.openTelemetryExporter;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
switch (config.openTelemetryExporter) {
|
|
121
|
+
case 'console': {
|
|
122
|
+
// Export spans to the console for testing purposes.
|
|
123
|
+
exporter = new sdk_node_1.tracing.ConsoleSpanExporter();
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case 'honeycomb': {
|
|
127
|
+
// Create a Honeycomb exporter with the appropriate metadata from the
|
|
128
|
+
// config we've been provided with.
|
|
129
|
+
const metadata = new grpc_js_1.Metadata();
|
|
130
|
+
metadata.set('x-honeycomb-team', config.honeycombApiKey);
|
|
131
|
+
metadata.set('x-honeycomb-dataset', config.honeycombDataset);
|
|
132
|
+
exporter = new exporter_otlp_grpc_1.OTLPTraceExporter({
|
|
133
|
+
url: 'grpc://api.honeycomb.io:443/',
|
|
134
|
+
credentials: grpc_js_1.credentials.createSsl(),
|
|
135
|
+
metadata,
|
|
136
|
+
});
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
default:
|
|
140
|
+
throw new Error(`Unknown OpenTelemetry exporter: ${config.openTelemetryExporter}`);
|
|
132
141
|
}
|
|
133
|
-
default:
|
|
134
|
-
throw new Error(`Unknown OpenTelemetry exporter: ${config.openTelemetryExporter}`);
|
|
135
142
|
}
|
|
136
143
|
let sampler;
|
|
137
|
-
switch (config.openTelemetrySamplerType) {
|
|
144
|
+
switch (config.openTelemetrySamplerType ?? 'always-on') {
|
|
138
145
|
case 'always-on': {
|
|
139
146
|
sampler = new core_1.AlwaysOnSampler();
|
|
140
147
|
break;
|
|
@@ -152,6 +159,20 @@ async function init(config) {
|
|
|
152
159
|
default:
|
|
153
160
|
throw new Error(`Unknown OpenTelemetry sampler type: ${config.openTelemetrySamplerType}`);
|
|
154
161
|
}
|
|
162
|
+
let spanProcessor;
|
|
163
|
+
switch (config.openTelemetrySpanProcessor ?? 'batch') {
|
|
164
|
+
case 'batch': {
|
|
165
|
+
spanProcessor = new FilterBatchSpanProcessor(exporter, filter);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case 'simple': {
|
|
169
|
+
spanProcessor = new sdk_trace_base_1.SimpleSpanProcessor(exporter);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
default: {
|
|
173
|
+
throw new Error(`Unknown OpenTelemetry span processor: ${config.openTelemetrySpanProcessor}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
155
176
|
// Much of this functionality is copied from `@opentelemetry/sdk-node`, but
|
|
156
177
|
// we can't use the SDK directly because of the fact that we load our config
|
|
157
178
|
// asynchronously. We need to initialize our instrumentations first; only
|
|
@@ -163,11 +184,10 @@ async function init(config) {
|
|
|
163
184
|
if (config.serviceName) {
|
|
164
185
|
resource = resource.merge(new resources_1.Resource({ [semantic_conventions_1.SemanticResourceAttributes.SERVICE_NAME]: config.serviceName }));
|
|
165
186
|
}
|
|
166
|
-
|
|
187
|
+
tracerProvider = new sdk_trace_node_1.NodeTracerProvider({
|
|
167
188
|
sampler,
|
|
168
189
|
resource,
|
|
169
190
|
});
|
|
170
|
-
const spanProcessor = new FilterBatchSpanProcessor(exporter, filter);
|
|
171
191
|
tracerProvider.addSpanProcessor(spanProcessor);
|
|
172
192
|
tracerProvider.register();
|
|
173
193
|
instrumentations.forEach((i) => i.setTracerProvider(tracerProvider));
|
|
@@ -180,13 +200,37 @@ exports.init = init;
|
|
|
180
200
|
async function shutdown() {
|
|
181
201
|
if (tracerProvider) {
|
|
182
202
|
await tracerProvider.shutdown();
|
|
203
|
+
tracerProvider = null;
|
|
183
204
|
}
|
|
184
205
|
}
|
|
185
206
|
exports.shutdown = shutdown;
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
207
|
+
async function instrumented(name, fn) {
|
|
208
|
+
return api_1.trace
|
|
209
|
+
.getTracer('default')
|
|
210
|
+
.startActiveSpan(name, async (span) => {
|
|
211
|
+
try {
|
|
212
|
+
const result = await fn(span);
|
|
213
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
span.setStatus({
|
|
218
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
219
|
+
message: e.message,
|
|
220
|
+
});
|
|
221
|
+
span.recordException(e);
|
|
222
|
+
throw e;
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
span.end();
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
exports.instrumented = instrumented;
|
|
230
|
+
var api_2 = require("@opentelemetry/api");
|
|
231
|
+
Object.defineProperty(exports, "trace", { enumerable: true, get: function () { return api_2.trace; } });
|
|
232
|
+
Object.defineProperty(exports, "context", { enumerable: true, get: function () { return api_2.context; } });
|
|
233
|
+
Object.defineProperty(exports, "SpanStatusCode", { enumerable: true, get: function () { return api_2.SpanStatusCode; } });
|
|
190
234
|
var core_2 = require("@opentelemetry/core");
|
|
191
235
|
Object.defineProperty(exports, "suppressTracing", { enumerable: true, get: function () { return core_2.suppressTracing; } });
|
|
192
236
|
//# 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":";;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
4
|
+
const chai_1 = require("chai");
|
|
5
|
+
const index_1 = require("./index");
|
|
6
|
+
const context_async_hooks_1 = require("@opentelemetry/context-async-hooks");
|
|
7
|
+
describe('instrumented', () => {
|
|
8
|
+
let contextManager;
|
|
9
|
+
let exporter = new sdk_node_1.tracing.InMemorySpanExporter();
|
|
10
|
+
before(async () => {
|
|
11
|
+
await (0, index_1.init)({
|
|
12
|
+
openTelemetryEnabled: true,
|
|
13
|
+
openTelemetryExporter: exporter,
|
|
14
|
+
openTelemetrySamplerType: 'always-on',
|
|
15
|
+
openTelemetrySpanProcessor: 'simple',
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
contextManager = new context_async_hooks_1.AsyncHooksContextManager();
|
|
20
|
+
index_1.context.setGlobalContextManager(contextManager.enable());
|
|
21
|
+
});
|
|
22
|
+
afterEach(async () => {
|
|
23
|
+
exporter.reset();
|
|
24
|
+
index_1.context.disable();
|
|
25
|
+
});
|
|
26
|
+
it('returns the value from the function', async () => {
|
|
27
|
+
const res = await (0, index_1.instrumented)('test', () => 'foo');
|
|
28
|
+
chai_1.assert.equal(res, 'foo');
|
|
29
|
+
});
|
|
30
|
+
it('records a span on success', async () => {
|
|
31
|
+
await (0, index_1.instrumented)('test-success', () => 'foo');
|
|
32
|
+
const spans = exporter.getFinishedSpans();
|
|
33
|
+
chai_1.assert.lengthOf(spans, 1);
|
|
34
|
+
chai_1.assert.equal(spans[0].name, 'test-success');
|
|
35
|
+
chai_1.assert.equal(spans[0].status.code, index_1.SpanStatusCode.OK);
|
|
36
|
+
});
|
|
37
|
+
it('records a span on failure', async () => {
|
|
38
|
+
let maybeError = null;
|
|
39
|
+
await (0, index_1.instrumented)('test-failure', () => {
|
|
40
|
+
throw new Error('foo');
|
|
41
|
+
}).catch((err) => {
|
|
42
|
+
maybeError = err;
|
|
43
|
+
});
|
|
44
|
+
// Ensure the error was propagated back to the caller.
|
|
45
|
+
chai_1.assert.isOk(maybeError);
|
|
46
|
+
chai_1.assert.equal(maybeError.message, 'foo');
|
|
47
|
+
// Ensure the correct span was recorded.
|
|
48
|
+
const spans = exporter.getFinishedSpans();
|
|
49
|
+
chai_1.assert.lengthOf(spans, 1);
|
|
50
|
+
chai_1.assert.equal(spans[0].name, 'test-failure');
|
|
51
|
+
chai_1.assert.equal(spans[0].status.code, index_1.SpanStatusCode.ERROR);
|
|
52
|
+
chai_1.assert.equal(spans[0].status.message, 'foo');
|
|
53
|
+
chai_1.assert.equal(spans[0].events[0].name, 'exception');
|
|
54
|
+
});
|
|
55
|
+
it('sets up context correctly', async () => {
|
|
56
|
+
const tracer = index_1.trace.getTracer('default');
|
|
57
|
+
const parentSpan = tracer.startSpan('parentSpan');
|
|
58
|
+
const parentContext = index_1.trace.setSpan(index_1.context.active(), parentSpan);
|
|
59
|
+
await (0, index_1.instrumented)('test', async () => {
|
|
60
|
+
const childContext = index_1.context.active();
|
|
61
|
+
chai_1.assert.notStrictEqual(childContext, parentContext);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/opentelemetry",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc",
|
|
7
|
-
"dev": "tsc --watch --preserveWatchOutput"
|
|
7
|
+
"dev": "tsc --watch --preserveWatchOutput",
|
|
8
|
+
"test": "mocha --no-config --require ts-node/register src/index.test.ts"
|
|
8
9
|
},
|
|
9
10
|
"dependencies": {
|
|
10
|
-
"@grpc/grpc-js": "^1.
|
|
11
|
-
"@opentelemetry/api": "^1.0
|
|
12
|
-
"@opentelemetry/core": "^1.
|
|
11
|
+
"@grpc/grpc-js": "^1.6.7",
|
|
12
|
+
"@opentelemetry/api": "^1.1.0",
|
|
13
|
+
"@opentelemetry/core": "^1.3.1",
|
|
13
14
|
"@opentelemetry/exporter-otlp-grpc": "^0.26.0",
|
|
14
|
-
"@opentelemetry/instrumentation-aws-sdk": "^0.
|
|
15
|
-
"@opentelemetry/instrumentation-connect": "^0.
|
|
16
|
-
"@opentelemetry/instrumentation-dns": "^0.
|
|
17
|
-
"@opentelemetry/instrumentation-express": "^0.
|
|
18
|
-
"@opentelemetry/instrumentation-http": "^0.
|
|
19
|
-
"@opentelemetry/instrumentation-pg": "^0.
|
|
20
|
-
"@opentelemetry/instrumentation-redis": "^0.
|
|
21
|
-
"@opentelemetry/resource-detector-aws": "^1.
|
|
22
|
-
"@opentelemetry/resources": "^1.
|
|
23
|
-
"@opentelemetry/sdk-node": "^0.
|
|
24
|
-
"@opentelemetry/sdk-trace-base": "^1.
|
|
25
|
-
"@opentelemetry/sdk-trace-node": "^1.
|
|
26
|
-
"@opentelemetry/semantic-conventions": "^1.
|
|
15
|
+
"@opentelemetry/instrumentation-aws-sdk": "^0.8.0",
|
|
16
|
+
"@opentelemetry/instrumentation-connect": "^0.29.0",
|
|
17
|
+
"@opentelemetry/instrumentation-dns": "^0.29.0",
|
|
18
|
+
"@opentelemetry/instrumentation-express": "^0.30.0",
|
|
19
|
+
"@opentelemetry/instrumentation-http": "^0.29.2",
|
|
20
|
+
"@opentelemetry/instrumentation-pg": "^0.30.0",
|
|
21
|
+
"@opentelemetry/instrumentation-redis": "^0.32.0",
|
|
22
|
+
"@opentelemetry/resource-detector-aws": "^1.1.1",
|
|
23
|
+
"@opentelemetry/resources": "^1.3.1",
|
|
24
|
+
"@opentelemetry/sdk-node": "^0.29.2",
|
|
25
|
+
"@opentelemetry/sdk-trace-base": "^1.3.1",
|
|
26
|
+
"@opentelemetry/sdk-trace-node": "^1.3.1",
|
|
27
|
+
"@opentelemetry/semantic-conventions": "^1.3.1"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
|
-
"
|
|
30
|
+
"@prairielearn/tsconfig": "*",
|
|
31
|
+
"mocha": "^10.0.0",
|
|
32
|
+
"ts-node": "^10.8.0",
|
|
33
|
+
"typescript": "^4.7.2"
|
|
30
34
|
}
|
|
31
35
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { tracing } from '@opentelemetry/sdk-node';
|
|
2
|
+
import { assert } from 'chai';
|
|
3
|
+
|
|
4
|
+
import { context, init, instrumented, shutdown, trace, SpanStatusCode } from './index';
|
|
5
|
+
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks';
|
|
6
|
+
|
|
7
|
+
describe('instrumented', () => {
|
|
8
|
+
let contextManager: AsyncHooksContextManager;
|
|
9
|
+
let exporter = new tracing.InMemorySpanExporter();
|
|
10
|
+
|
|
11
|
+
before(async () => {
|
|
12
|
+
await init({
|
|
13
|
+
openTelemetryEnabled: true,
|
|
14
|
+
openTelemetryExporter: exporter,
|
|
15
|
+
openTelemetrySamplerType: 'always-on',
|
|
16
|
+
openTelemetrySpanProcessor: 'simple',
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
contextManager = new AsyncHooksContextManager();
|
|
22
|
+
context.setGlobalContextManager(contextManager.enable());
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(async () => {
|
|
26
|
+
exporter.reset();
|
|
27
|
+
context.disable();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('returns the value from the function', async () => {
|
|
31
|
+
const res = await instrumented('test', () => 'foo');
|
|
32
|
+
assert.equal(res, 'foo');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('records a span on success', async () => {
|
|
36
|
+
await instrumented('test-success', () => 'foo');
|
|
37
|
+
|
|
38
|
+
const spans = exporter.getFinishedSpans();
|
|
39
|
+
assert.lengthOf(spans, 1);
|
|
40
|
+
assert.equal(spans[0].name, 'test-success');
|
|
41
|
+
assert.equal(spans[0].status.code, SpanStatusCode.OK);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('records a span on failure', async () => {
|
|
45
|
+
let maybeError = null;
|
|
46
|
+
await instrumented('test-failure', () => {
|
|
47
|
+
throw new Error('foo');
|
|
48
|
+
}).catch((err) => {
|
|
49
|
+
maybeError = err;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Ensure the error was propagated back to the caller.
|
|
53
|
+
assert.isOk(maybeError);
|
|
54
|
+
assert.equal(maybeError.message, 'foo');
|
|
55
|
+
|
|
56
|
+
// Ensure the correct span was recorded.
|
|
57
|
+
const spans = exporter.getFinishedSpans();
|
|
58
|
+
assert.lengthOf(spans, 1);
|
|
59
|
+
assert.equal(spans[0].name, 'test-failure');
|
|
60
|
+
assert.equal(spans[0].status.code, SpanStatusCode.ERROR);
|
|
61
|
+
assert.equal(spans[0].status.message, 'foo');
|
|
62
|
+
assert.equal(spans[0].events[0].name, 'exception');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('sets up context correctly', async () => {
|
|
66
|
+
const tracer = trace.getTracer('default');
|
|
67
|
+
const parentSpan = tracer.startSpan('parentSpan');
|
|
68
|
+
const parentContext = trace.setSpan(context.active(), parentSpan);
|
|
69
|
+
|
|
70
|
+
await instrumented('test', async () => {
|
|
71
|
+
const childContext = context.active();
|
|
72
|
+
assert.notStrictEqual(childContext, parentContext);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import process from 'process';
|
|
2
1
|
import { Metadata, credentials } from '@grpc/grpc-js';
|
|
3
2
|
|
|
4
3
|
import { tracing } from '@opentelemetry/sdk-node';
|
|
5
4
|
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
|
6
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
SpanExporter,
|
|
7
|
+
ReadableSpan,
|
|
8
|
+
SpanProcessor,
|
|
9
|
+
SimpleSpanProcessor,
|
|
10
|
+
} from '@opentelemetry/sdk-trace-base';
|
|
7
11
|
import { detectResources, Resource } from '@opentelemetry/resources';
|
|
8
12
|
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
|
9
13
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-otlp-grpc';
|
|
10
14
|
import { ExpressLayerType } from '@opentelemetry/instrumentation-express';
|
|
11
15
|
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
12
|
-
import { Sampler } from '@opentelemetry/api';
|
|
16
|
+
import { Sampler, Span, SpanStatusCode, context, trace } from '@opentelemetry/api';
|
|
13
17
|
import {
|
|
14
18
|
ParentBasedSampler,
|
|
15
19
|
TraceIdRatioBasedSampler,
|
|
@@ -30,6 +34,7 @@ import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';
|
|
|
30
34
|
// Resource detectors go here.
|
|
31
35
|
import { awsEc2Detector } from '@opentelemetry/resource-detector-aws';
|
|
32
36
|
import { processDetector, envDetector } from '@opentelemetry/resources';
|
|
37
|
+
import { createBaggage } from '@opentelemetry/api/build/src/baggage/utils';
|
|
33
38
|
|
|
34
39
|
/**
|
|
35
40
|
* Extends `BatchSpanProcessor` to give it the ability to filter out spans
|
|
@@ -115,9 +120,10 @@ let tracerProvider: NodeTracerProvider;
|
|
|
115
120
|
|
|
116
121
|
export interface OpenTelemetryConfig {
|
|
117
122
|
openTelemetryEnabled: boolean;
|
|
118
|
-
openTelemetryExporter
|
|
119
|
-
openTelemetrySamplerType
|
|
123
|
+
openTelemetryExporter: 'console' | 'honeycomb' | SpanExporter;
|
|
124
|
+
openTelemetrySamplerType: 'always-on' | 'always-off' | 'trace-id-ratio';
|
|
120
125
|
openTelemetrySampleRate?: number;
|
|
126
|
+
openTelemetrySpanProcessor?: 'batch' | 'simple';
|
|
121
127
|
honeycombApiKey?: string;
|
|
122
128
|
honeycombDataset?: string;
|
|
123
129
|
serviceName?: string;
|
|
@@ -141,33 +147,37 @@ export async function init(config: OpenTelemetryConfig) {
|
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
let exporter: SpanExporter;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
150
|
+
if (typeof config.openTelemetryExporter === 'object') {
|
|
151
|
+
exporter = config.openTelemetryExporter;
|
|
152
|
+
} else {
|
|
153
|
+
switch (config.openTelemetryExporter) {
|
|
154
|
+
case 'console': {
|
|
155
|
+
// Export spans to the console for testing purposes.
|
|
156
|
+
exporter = new tracing.ConsoleSpanExporter();
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case 'honeycomb': {
|
|
160
|
+
// Create a Honeycomb exporter with the appropriate metadata from the
|
|
161
|
+
// config we've been provided with.
|
|
162
|
+
const metadata = new Metadata();
|
|
163
|
+
|
|
164
|
+
metadata.set('x-honeycomb-team', config.honeycombApiKey);
|
|
165
|
+
metadata.set('x-honeycomb-dataset', config.honeycombDataset);
|
|
166
|
+
|
|
167
|
+
exporter = new OTLPTraceExporter({
|
|
168
|
+
url: 'grpc://api.honeycomb.io:443/',
|
|
169
|
+
credentials: credentials.createSsl(),
|
|
170
|
+
metadata,
|
|
171
|
+
});
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
default:
|
|
175
|
+
throw new Error(`Unknown OpenTelemetry exporter: ${config.openTelemetryExporter}`);
|
|
164
176
|
}
|
|
165
|
-
default:
|
|
166
|
-
throw new Error(`Unknown OpenTelemetry exporter: ${config.openTelemetryExporter}`);
|
|
167
177
|
}
|
|
168
178
|
|
|
169
179
|
let sampler: Sampler;
|
|
170
|
-
switch (config.openTelemetrySamplerType) {
|
|
180
|
+
switch (config.openTelemetrySamplerType ?? 'always-on') {
|
|
171
181
|
case 'always-on': {
|
|
172
182
|
sampler = new AlwaysOnSampler();
|
|
173
183
|
break;
|
|
@@ -186,6 +196,21 @@ export async function init(config: OpenTelemetryConfig) {
|
|
|
186
196
|
throw new Error(`Unknown OpenTelemetry sampler type: ${config.openTelemetrySamplerType}`);
|
|
187
197
|
}
|
|
188
198
|
|
|
199
|
+
let spanProcessor: SpanProcessor;
|
|
200
|
+
switch (config.openTelemetrySpanProcessor ?? 'batch') {
|
|
201
|
+
case 'batch': {
|
|
202
|
+
spanProcessor = new FilterBatchSpanProcessor(exporter, filter);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
case 'simple': {
|
|
206
|
+
spanProcessor = new SimpleSpanProcessor(exporter);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
default: {
|
|
210
|
+
throw new Error(`Unknown OpenTelemetry span processor: ${config.openTelemetrySpanProcessor}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
189
214
|
// Much of this functionality is copied from `@opentelemetry/sdk-node`, but
|
|
190
215
|
// we can't use the SDK directly because of the fact that we load our config
|
|
191
216
|
// asynchronously. We need to initialize our instrumentations first; only
|
|
@@ -202,11 +227,10 @@ export async function init(config: OpenTelemetryConfig) {
|
|
|
202
227
|
);
|
|
203
228
|
}
|
|
204
229
|
|
|
205
|
-
|
|
230
|
+
tracerProvider = new NodeTracerProvider({
|
|
206
231
|
sampler,
|
|
207
232
|
resource,
|
|
208
233
|
});
|
|
209
|
-
const spanProcessor = new FilterBatchSpanProcessor(exporter, filter);
|
|
210
234
|
tracerProvider.addSpanProcessor(spanProcessor);
|
|
211
235
|
tracerProvider.register();
|
|
212
236
|
|
|
@@ -220,8 +244,33 @@ export async function init(config: OpenTelemetryConfig) {
|
|
|
220
244
|
export async function shutdown(): Promise<void> {
|
|
221
245
|
if (tracerProvider) {
|
|
222
246
|
await tracerProvider.shutdown();
|
|
247
|
+
tracerProvider = null;
|
|
223
248
|
}
|
|
224
249
|
}
|
|
225
250
|
|
|
251
|
+
export async function instrumented<T>(
|
|
252
|
+
name: string,
|
|
253
|
+
fn: (span: Span) => Promise<T> | T
|
|
254
|
+
): Promise<T> {
|
|
255
|
+
return trace
|
|
256
|
+
.getTracer('default')
|
|
257
|
+
.startActiveSpan<(span: Span) => Promise<T>>(name, async (span) => {
|
|
258
|
+
try {
|
|
259
|
+
const result = await fn(span);
|
|
260
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
261
|
+
return result;
|
|
262
|
+
} catch (e) {
|
|
263
|
+
span.setStatus({
|
|
264
|
+
code: SpanStatusCode.ERROR,
|
|
265
|
+
message: e.message,
|
|
266
|
+
});
|
|
267
|
+
span.recordException(e);
|
|
268
|
+
throw e;
|
|
269
|
+
} finally {
|
|
270
|
+
span.end();
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
226
275
|
export { trace, context, SpanStatusCode } from '@opentelemetry/api';
|
|
227
276
|
export { suppressTracing } from '@opentelemetry/core';
|
package/tsconfig.json
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "@prairielearn/tsconfig",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"allowJs": true,
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"esModuleInterop": true,
|
|
6
4
|
"outDir": "./dist",
|
|
7
|
-
"rootDir": "src
|
|
8
|
-
"sourceMap": true,
|
|
9
|
-
// This package will only be used server-side on Node 14+, so target the
|
|
10
|
-
// newest version of the ES spec that Node 14 supports.
|
|
11
|
-
"target": "ES2020",
|
|
12
|
-
// However, we don't yet make extensive use of ES Modules, so specifically
|
|
13
|
-
// compile `import`/`export` down to CommonJS.
|
|
14
|
-
"module": "CommonJS",
|
|
5
|
+
"rootDir": "./src",
|
|
15
6
|
}
|
|
16
7
|
}
|