@prairielearn/opentelemetry 2.1.16 → 3.0.1
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 +20 -0
- package/dist/init.d.ts +4 -0
- package/dist/init.js +31 -36
- package/dist/init.js.map +1 -1
- package/dist/metrics.test.js +10 -9
- package/dist/metrics.test.js.map +1 -1
- package/package.json +24 -24
- package/src/init.ts +32 -39
- package/src/metrics.test.ts +10 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @prairielearn/opentelemetry
|
|
2
2
|
|
|
3
|
+
## 3.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b55261c: Upgrade to TypeScript 5.9
|
|
8
|
+
|
|
9
|
+
## 3.0.0
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- a7d1ad9: Always configure `NodeTracerProvider`, even when `openTelemetryEnabled === false`.
|
|
14
|
+
|
|
15
|
+
This change is being made to ensure that Sentry's request isolation works correctly, as it relies on the `NodeTracerProvider` being set up.
|
|
16
|
+
|
|
17
|
+
- 423ab32: Upgrade to v2 of the OpenTelemetry packages
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 23adb05: Upgrade all JavaScript dependencies
|
|
22
|
+
|
|
3
23
|
## 2.1.16
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/init.d.ts
CHANGED
|
@@ -22,6 +22,10 @@ export type OpenTelemetryConfig = OpenTelemetryConfigEnabled | OpenTelemetryConf
|
|
|
22
22
|
* Should be called once we've loaded our config; this will allow us to set up
|
|
23
23
|
* the correct metadata for the Honeycomb exporter. We don't actually have that
|
|
24
24
|
* information available until we've loaded our config.
|
|
25
|
+
*
|
|
26
|
+
* Note that even when `openTelemetryEnabled` is `false`, we'll still configure
|
|
27
|
+
* the `NodeTraceProvider` and instrumentations, as Sentry relies on that for
|
|
28
|
+
* scope isolation. However, we won't actually set up any exporters.
|
|
25
29
|
*/
|
|
26
30
|
export declare function init(config: OpenTelemetryConfig): Promise<void>;
|
|
27
31
|
/**
|
package/dist/init.js
CHANGED
|
@@ -13,11 +13,11 @@ import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
|
|
|
13
13
|
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
|
|
14
14
|
import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';
|
|
15
15
|
import { awsEc2Detector } from '@opentelemetry/resource-detector-aws';
|
|
16
|
-
import {
|
|
16
|
+
import { detectResources, envDetector, processDetector, resourceFromAttributes, } from '@opentelemetry/resources';
|
|
17
17
|
import { AggregationTemporality, ConsoleMetricExporter, MeterProvider, PeriodicExportingMetricReader, } from '@opentelemetry/sdk-metrics';
|
|
18
|
-
import { AlwaysOffSampler, AlwaysOnSampler, BatchSpanProcessor, ConsoleSpanExporter, ParentBasedSampler, SimpleSpanProcessor, TraceIdRatioBasedSampler, } from '@opentelemetry/sdk-trace-base';
|
|
18
|
+
import { AlwaysOffSampler, AlwaysOnSampler, BatchSpanProcessor, ConsoleSpanExporter, NoopSpanProcessor, ParentBasedSampler, SimpleSpanProcessor, TraceIdRatioBasedSampler, } from '@opentelemetry/sdk-trace-base';
|
|
19
19
|
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
|
20
|
-
import {
|
|
20
|
+
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
21
21
|
/**
|
|
22
22
|
* Extends `BatchSpanProcessor` to give it the ability to filter out spans
|
|
23
23
|
* before they're queued up to send. This enhances our sampling process so
|
|
@@ -110,7 +110,7 @@ function getHoneycombMetadata(config, datasetSuffix = '') {
|
|
|
110
110
|
return metadata;
|
|
111
111
|
}
|
|
112
112
|
function getTraceExporter(config) {
|
|
113
|
-
if (!config.openTelemetryExporter)
|
|
113
|
+
if (!config.openTelemetryEnabled || !config.openTelemetryExporter)
|
|
114
114
|
return null;
|
|
115
115
|
if (typeof config.openTelemetryExporter === 'object') {
|
|
116
116
|
return config.openTelemetryExporter;
|
|
@@ -131,7 +131,7 @@ function getTraceExporter(config) {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
function getMetricExporter(config) {
|
|
134
|
-
if (!config.openTelemetryMetricExporter)
|
|
134
|
+
if (!config.openTelemetryEnabled || !config.openTelemetryMetricExporter)
|
|
135
135
|
return null;
|
|
136
136
|
if (typeof config.openTelemetryMetricExporter === 'object') {
|
|
137
137
|
return config.openTelemetryMetricExporter;
|
|
@@ -156,12 +156,14 @@ function getMetricExporter(config) {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
function getSpanProcessor(config) {
|
|
159
|
+
if (!config.openTelemetryEnabled)
|
|
160
|
+
return new NoopSpanProcessor();
|
|
159
161
|
if (typeof config.openTelemetrySpanProcessor === 'object') {
|
|
160
162
|
return config.openTelemetrySpanProcessor;
|
|
161
163
|
}
|
|
162
164
|
const traceExporter = getTraceExporter(config);
|
|
163
165
|
if (!traceExporter)
|
|
164
|
-
return
|
|
166
|
+
return new NoopSpanProcessor();
|
|
165
167
|
switch (config.openTelemetrySpanProcessor ?? 'batch') {
|
|
166
168
|
case 'batch': {
|
|
167
169
|
return new FilterBatchSpanProcessor(traceExporter, filter);
|
|
@@ -174,49 +176,44 @@ function getSpanProcessor(config) {
|
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
* information available until we've loaded our config.
|
|
181
|
-
*/
|
|
182
|
-
export async function init(config) {
|
|
183
|
-
if (!config.openTelemetryEnabled) {
|
|
184
|
-
// If not enabled, do nothing. We used to disable the instrumentations, but
|
|
185
|
-
// per maintainers, that can actually be problematic. See the comments on
|
|
186
|
-
// https://github.com/open-telemetry/opentelemetry-js-contrib/issues/970
|
|
187
|
-
// The Express instrumentation also logs a benign error, which can be
|
|
188
|
-
// confusing to users. There's a fix in progress if we want to switch back
|
|
189
|
-
// to disabling instrumentations in the future:
|
|
190
|
-
// https://github.com/open-telemetry/opentelemetry-js-contrib/pull/972
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
const metricExporter = getMetricExporter(config);
|
|
194
|
-
const spanProcessor = getSpanProcessor(config);
|
|
195
|
-
let sampler;
|
|
179
|
+
function getSampler(config) {
|
|
180
|
+
if (!config.openTelemetryEnabled)
|
|
181
|
+
return new AlwaysOffSampler();
|
|
196
182
|
switch (config.openTelemetrySamplerType ?? 'always-on') {
|
|
197
183
|
case 'always-on': {
|
|
198
|
-
|
|
199
|
-
break;
|
|
184
|
+
return new AlwaysOnSampler();
|
|
200
185
|
}
|
|
201
186
|
case 'always-off': {
|
|
202
|
-
|
|
203
|
-
break;
|
|
187
|
+
return new AlwaysOffSampler();
|
|
204
188
|
}
|
|
205
189
|
case 'trace-id-ratio': {
|
|
206
|
-
|
|
190
|
+
return new ParentBasedSampler({
|
|
207
191
|
root: new TraceIdRatioBasedSampler(config.openTelemetrySampleRate),
|
|
208
192
|
});
|
|
209
|
-
break;
|
|
210
193
|
}
|
|
211
194
|
default:
|
|
212
195
|
throw new Error(`Unknown OpenTelemetry sampler type: ${config.openTelemetrySamplerType}`);
|
|
213
196
|
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Should be called once we've loaded our config; this will allow us to set up
|
|
200
|
+
* the correct metadata for the Honeycomb exporter. We don't actually have that
|
|
201
|
+
* information available until we've loaded our config.
|
|
202
|
+
*
|
|
203
|
+
* Note that even when `openTelemetryEnabled` is `false`, we'll still configure
|
|
204
|
+
* the `NodeTraceProvider` and instrumentations, as Sentry relies on that for
|
|
205
|
+
* scope isolation. However, we won't actually set up any exporters.
|
|
206
|
+
*/
|
|
207
|
+
export async function init(config) {
|
|
208
|
+
const metricExporter = getMetricExporter(config);
|
|
209
|
+
const spanProcessor = getSpanProcessor(config);
|
|
210
|
+
const sampler = getSampler(config);
|
|
214
211
|
// Much of this functionality is copied from `@opentelemetry/sdk-node`, but
|
|
215
212
|
// we can't use the SDK directly because of the fact that we load our config
|
|
216
213
|
// asynchronously. We need to initialize our instrumentations first; only
|
|
217
214
|
// then can we actually start requiring all of our code that loads our config
|
|
218
215
|
// and ultimately tells us how to configure OpenTelemetry.
|
|
219
|
-
let resource =
|
|
216
|
+
let resource = detectResources({
|
|
220
217
|
// The AWS resource detector always tries to reach out to the EC2 metadata
|
|
221
218
|
// service endpoint. When running locally, or otherwise in a non-AWS environment,
|
|
222
219
|
// this will typically fail immediately wih `EHOSTDOWN`, but will sometimes wait
|
|
@@ -235,16 +232,14 @@ export async function init(config) {
|
|
|
235
232
|
].filter((d) => !!d),
|
|
236
233
|
});
|
|
237
234
|
if (config.serviceName) {
|
|
238
|
-
resource = resource.merge(
|
|
235
|
+
resource = resource.merge(resourceFromAttributes({ [ATTR_SERVICE_NAME]: config.serviceName }));
|
|
239
236
|
}
|
|
240
237
|
// Set up tracing instrumentation.
|
|
241
238
|
const nodeTracerProvider = new NodeTracerProvider({
|
|
242
239
|
sampler,
|
|
243
240
|
resource,
|
|
241
|
+
spanProcessors: [spanProcessor].filter((p) => !!p),
|
|
244
242
|
});
|
|
245
|
-
if (spanProcessor) {
|
|
246
|
-
nodeTracerProvider.addSpanProcessor(spanProcessor);
|
|
247
|
-
}
|
|
248
243
|
nodeTracerProvider.register({
|
|
249
244
|
contextManager: config.contextManager,
|
|
250
245
|
});
|
package/dist/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata, credentials } from '@grpc/grpc-js';\nimport { type ContextManager, metrics } from '@opentelemetry/api';\nimport { hrTimeToMilliseconds } from '@opentelemetry/core';\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';\nimport { OTLPTraceExporter as OTLPTraceExporterHttp } from '@opentelemetry/exporter-trace-otlp-http';\nimport { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk';\nimport { ConnectInstrumentation } from '@opentelemetry/instrumentation-connect';\nimport { DnsInstrumentation } from '@opentelemetry/instrumentation-dns';\nimport { ExpressInstrumentation, ExpressLayerType } from '@opentelemetry/instrumentation-express';\nimport { HttpInstrumentation } from '@opentelemetry/instrumentation-http';\nimport { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';\nimport { PgInstrumentation } from '@opentelemetry/instrumentation-pg';\nimport { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';\nimport { awsEc2Detector } from '@opentelemetry/resource-detector-aws';\nimport {\n Resource,\n detectResourcesSync,\n envDetector,\n processDetector,\n} from '@opentelemetry/resources';\nimport {\n AggregationTemporality,\n ConsoleMetricExporter,\n MeterProvider,\n PeriodicExportingMetricReader,\n type PushMetricExporter,\n} from '@opentelemetry/sdk-metrics';\nimport {\n AlwaysOffSampler,\n AlwaysOnSampler,\n BatchSpanProcessor,\n ConsoleSpanExporter,\n ParentBasedSampler,\n type ReadableSpan,\n type Sampler,\n SimpleSpanProcessor,\n type SpanExporter,\n type SpanProcessor,\n TraceIdRatioBasedSampler,\n} from '@opentelemetry/sdk-trace-base';\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';\nimport { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';\n\n/**\n * Extends `BatchSpanProcessor` to give it the ability to filter out spans\n * before they're queued up to send. This enhances our sampling process so\n * that we can filter spans _after_ they've been emitted.\n */\nclass FilterBatchSpanProcessor extends BatchSpanProcessor {\n private filter: (span: ReadableSpan) => boolean;\n\n constructor(exporter: SpanExporter, filter: (span: ReadableSpan) => boolean) {\n super(exporter);\n this.filter = filter;\n }\n\n /**\n * This is invoked after a span is \"finalized\". `super.onEnd` will queue up\n * the span to be exported, but if we don't call that, we can just drop the\n * span and the parent will be none the wiser!\n */\n onEnd(span: ReadableSpan) {\n if (!this.filter(span)) return;\n\n super.onEnd(span);\n }\n}\n\n/**\n * This will be used with our {@link FilterBatchSpanProcessor} to filter out\n * events that we're not interested in. This helps reduce our event volume\n * but still gives us fine-grained control over which events we keep.\n */\nfunction filter(span: ReadableSpan) {\n if (span.name === 'pg-pool.connect') {\n // Looking at historical data, this generally happens in under a millisecond,\n // precisely because we maintain a pool of long-lived connections. The only\n // time obtaining a client should take longer than that is if we're\n // establishing a connection for the first time, which should happen only at\n // bootup, or if a connection errors out. Those are the cases we're\n // interested in, so we'll filter accordingly.\n return hrTimeToMilliseconds(span.duration) > 1;\n }\n\n // Always return true so that we default to including a span.\n return true;\n}\n\n// When adding new instrumentation here, add the corresponding packages to\n// `commonjs-preloads.ts` so that we can ensure that they're loaded via CJS\n// before anything tries to load them via CJS. This is necessary because the\n// instrumentations can't hook into the ESM loader.\nconst instrumentations = [\n new AwsInstrumentation(),\n new ConnectInstrumentation(),\n new DnsInstrumentation(),\n new ExpressInstrumentation({\n // We use a lot of middleware; it makes the traces way too noisy. If we\n // want telemetry on a particular middleware, we should instrument it\n // manually.\n ignoreLayersType: [ExpressLayerType.MIDDLEWARE],\n ignoreLayers: [\n // These don't provide useful information to us.\n 'router - /',\n 'request handler - /*',\n ],\n }),\n new HttpInstrumentation({\n ignoreIncomingRequestHook(req) {\n return [\n // socket.io requests are generally just long-polling; they don't add\n // useful information for us.\n /\\/socket.io\\//,\n // We get several of these per second; they just chew through our event quota.\n // They don't really do anything interesting anyways.\n /\\/pl\\/webhooks\\/ping/,\n ].some((re) => re.test(req.url ?? '/'));\n },\n }),\n new IORedisInstrumentation(),\n new PgInstrumentation(),\n new RedisInstrumentation(),\n];\n\n// Enable all instrumentations now, even though we haven't configured our\n// span processors or trace exporters yet. We'll set those up later.\ninstrumentations.forEach((i) => {\n i.enable();\n});\n\nlet tracerProvider: NodeTracerProvider | null;\n\ninterface OpenTelemetryConfigEnabled {\n openTelemetryEnabled: boolean;\n openTelemetryExporter?: 'console' | 'honeycomb' | 'jaeger' | SpanExporter | null;\n openTelemetryMetricExporter?: 'console' | 'honeycomb' | PushMetricExporter | null;\n openTelemetryMetricExportIntervalMillis?: number;\n openTelemetrySamplerType: 'always-on' | 'always-off' | 'trace-id-ratio';\n openTelemetrySampleRate?: number;\n openTelemetrySpanProcessor?: 'batch' | 'simple' | SpanProcessor;\n contextManager?: ContextManager;\n honeycombApiKey?: string | null;\n honeycombDataset?: string | null;\n serviceName?: string;\n}\n\n// When we know for sure that OpenTelemetry is disabled, we won't require\n// any other attributes to be set.\ninterface OpenTelemetryConfigDisabled extends Partial<OpenTelemetryConfigEnabled> {\n openTelemetryEnabled: false;\n}\n\nexport type OpenTelemetryConfig = OpenTelemetryConfigEnabled | OpenTelemetryConfigDisabled;\n\nfunction getHoneycombMetadata(config: OpenTelemetryConfig, datasetSuffix = ''): Metadata {\n if (!config.honeycombApiKey) throw new Error('Missing Honeycomb API key');\n if (!config.honeycombDataset) throw new Error('Missing Honeycomb dataset');\n\n const metadata = new Metadata();\n\n metadata.set('x-honeycomb-team', config.honeycombApiKey);\n metadata.set('x-honeycomb-dataset', config.honeycombDataset + datasetSuffix);\n\n return metadata;\n}\n\nfunction getTraceExporter(config: OpenTelemetryConfig): SpanExporter | null {\n if (!config.openTelemetryExporter) return null;\n\n if (typeof config.openTelemetryExporter === 'object') {\n return config.openTelemetryExporter;\n }\n\n switch (config.openTelemetryExporter) {\n case 'console':\n return new ConsoleSpanExporter();\n case 'honeycomb':\n return new OTLPTraceExporter({\n url: 'grpc://api.honeycomb.io:443/',\n credentials: credentials.createSsl(),\n metadata: getHoneycombMetadata(config),\n });\n case 'jaeger':\n return new OTLPTraceExporterHttp();\n default:\n throw new Error(`Unknown OpenTelemetry exporter: ${config.openTelemetryExporter}`);\n }\n}\n\nfunction getMetricExporter(config: OpenTelemetryConfig): PushMetricExporter | null {\n if (!config.openTelemetryMetricExporter) return null;\n\n if (typeof config.openTelemetryMetricExporter === 'object') {\n return config.openTelemetryMetricExporter;\n }\n\n switch (config.openTelemetryMetricExporter) {\n case 'console':\n return new ConsoleMetricExporter();\n case 'honeycomb':\n return new OTLPMetricExporter({\n url: 'grpc://api.honeycomb.io:443/',\n credentials: credentials.createSsl(),\n // Honeycomb recommends using a separate dataset for metrics, so we'll\n // adopt the convention of appending '-metrics' to the dataset name.\n metadata: getHoneycombMetadata(config, '-metrics'),\n // Delta temporality means that sums, histograms, etc. will reset each\n // time data is collected. This more closely matches how we want to\n // observe our metrics than the default cumulative temporality.\n temporalityPreference: AggregationTemporality.DELTA,\n });\n default:\n throw new Error(\n `Unknown OpenTelemetry metric exporter: ${config.openTelemetryMetricExporter}`,\n );\n }\n}\n\nfunction getSpanProcessor(config: OpenTelemetryConfig): SpanProcessor | null {\n if (typeof config.openTelemetrySpanProcessor === 'object') {\n return config.openTelemetrySpanProcessor;\n }\n\n const traceExporter = getTraceExporter(config);\n if (!traceExporter) return null;\n\n switch (config.openTelemetrySpanProcessor ?? 'batch') {\n case 'batch': {\n return new FilterBatchSpanProcessor(traceExporter, filter);\n }\n case 'simple': {\n return new SimpleSpanProcessor(traceExporter);\n }\n default: {\n throw new Error(`Unknown OpenTelemetry span processor: ${config.openTelemetrySpanProcessor}`);\n }\n }\n}\n\n/**\n * Should be called once we've loaded our config; this will allow us to set up\n * the correct metadata for the Honeycomb exporter. We don't actually have that\n * information available until we've loaded our config.\n */\nexport async function init(config: OpenTelemetryConfig) {\n if (!config.openTelemetryEnabled) {\n // If not enabled, do nothing. We used to disable the instrumentations, but\n // per maintainers, that can actually be problematic. See the comments on\n // https://github.com/open-telemetry/opentelemetry-js-contrib/issues/970\n // The Express instrumentation also logs a benign error, which can be\n // confusing to users. There's a fix in progress if we want to switch back\n // to disabling instrumentations in the future:\n // https://github.com/open-telemetry/opentelemetry-js-contrib/pull/972\n return;\n }\n\n const metricExporter = getMetricExporter(config);\n const spanProcessor = getSpanProcessor(config);\n\n let sampler: Sampler;\n switch (config.openTelemetrySamplerType ?? 'always-on') {\n case 'always-on': {\n sampler = new AlwaysOnSampler();\n break;\n }\n case 'always-off': {\n sampler = new AlwaysOffSampler();\n break;\n }\n case 'trace-id-ratio': {\n sampler = new ParentBasedSampler({\n root: new TraceIdRatioBasedSampler(config.openTelemetrySampleRate),\n });\n break;\n }\n default:\n throw new Error(`Unknown OpenTelemetry sampler type: ${config.openTelemetrySamplerType}`);\n }\n\n // Much of this functionality is copied from `@opentelemetry/sdk-node`, but\n // we can't use the SDK directly because of the fact that we load our config\n // asynchronously. We need to initialize our instrumentations first; only\n // then can we actually start requiring all of our code that loads our config\n // and ultimately tells us how to configure OpenTelemetry.\n\n let resource = detectResourcesSync({\n // The AWS resource detector always tries to reach out to the EC2 metadata\n // service endpoint. When running locally, or otherwise in a non-AWS environment,\n // this will typically fail immediately wih `EHOSTDOWN`, but will sometimes wait\n // 5 seconds before failing with a network timeout error. This causes problems\n // when running tests, as 5 seconds is longer than Mocha lets tests and hooks run\n // for by default. This causes nondeterministic test failures when the EC2 metadata\n // request fails with a network timeout.\n //\n // To work around this, the AWS resource detector is only enabled when running in\n // a production environment. In general this is reasonable, as we only care about\n // AWS resource detection in production-like environments.\n detectors: [\n process.env.NODE_ENV === 'production' ? awsEc2Detector : null,\n processDetector,\n envDetector,\n ].filter((d) => !!d),\n });\n\n if (config.serviceName) {\n resource = resource.merge(\n new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: config.serviceName }),\n );\n }\n\n // Set up tracing instrumentation.\n const nodeTracerProvider = new NodeTracerProvider({\n sampler,\n resource,\n });\n if (spanProcessor) {\n nodeTracerProvider.addSpanProcessor(spanProcessor);\n }\n nodeTracerProvider.register({\n contextManager: config.contextManager,\n });\n instrumentations.forEach((i) => i.setTracerProvider(nodeTracerProvider));\n\n // Save the provider so we can shut it down later.\n tracerProvider = nodeTracerProvider;\n\n // Set up metrics instrumentation if it's enabled.\n if (metricExporter) {\n const meterProvider = new MeterProvider({\n resource,\n readers: [\n new PeriodicExportingMetricReader({\n exporter: metricExporter,\n exportIntervalMillis: config.openTelemetryMetricExportIntervalMillis ?? 30_000,\n }),\n ],\n });\n metrics.setGlobalMeterProvider(meterProvider);\n }\n}\n\n/**\n * Gracefully shuts down the OpenTelemetry instrumentation. Should be called\n * when a `SIGTERM` signal is handled.\n */\nexport async function shutdown(): Promise<void> {\n if (tracerProvider) {\n await tracerProvider.shutdown();\n tracerProvider = null;\n }\n}\n\n/**\n * Disables all OpenTelemetry instrumentations. This is useful for tests that\n * need to access the unwrapped modules.\n */\nexport function disableInstrumentations() {\n instrumentations.forEach((i) => i.disable());\n}\n"]}
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAuB,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,IAAI,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrG,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EACL,eAAe,EACf,WAAW,EACX,eAAe,EACf,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,6BAA6B,GAE9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAGlB,mBAAmB,EAGnB,wBAAwB,GACzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAExE;;;;GAIG;AACH,MAAM,wBAAyB,SAAQ,kBAAkB;IAC/C,MAAM,CAAkC;IAEhD,YAAY,QAAsB,EAAE,MAAuC;QACzE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAkB;QACtB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,OAAO;QAE/B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;CACF;AAED;;;;GAIG;AACH,SAAS,MAAM,CAAC,IAAkB;IAChC,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACpC,6EAA6E;QAC7E,2EAA2E;QAC3E,mEAAmE;QACnE,4EAA4E;QAC5E,mEAAmE;QACnE,8CAA8C;QAC9C,OAAO,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,6DAA6D;IAC7D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,mDAAmD;AACnD,MAAM,gBAAgB,GAAG;IACvB,IAAI,kBAAkB,EAAE;IACxB,IAAI,sBAAsB,EAAE;IAC5B,IAAI,kBAAkB,EAAE;IACxB,IAAI,sBAAsB,CAAC;QACzB,uEAAuE;QACvE,qEAAqE;QACrE,YAAY;QACZ,gBAAgB,EAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC;QAC/C,YAAY,EAAE;YACZ,gDAAgD;YAChD,YAAY;YACZ,sBAAsB;SACvB;KACF,CAAC;IACF,IAAI,mBAAmB,CAAC;QACtB,yBAAyB,CAAC,GAAG;YAC3B,OAAO;gBACL,qEAAqE;gBACrE,6BAA6B;gBAC7B,eAAe;gBACf,8EAA8E;gBAC9E,qDAAqD;gBACrD,sBAAsB;aACvB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;IACF,IAAI,sBAAsB,EAAE;IAC5B,IAAI,iBAAiB,EAAE;IACvB,IAAI,oBAAoB,EAAE;CAC3B,CAAC;AAEF,yEAAyE;AACzE,oEAAoE;AACpE,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;IAC7B,CAAC,CAAC,MAAM,EAAE,CAAC;AACb,CAAC,CAAC,CAAC;AAEH,IAAI,cAAyC,CAAC;AAwB9C,SAAS,oBAAoB,CAAC,MAA2B,EAAE,aAAa,GAAG,EAAE;IAC3E,IAAI,CAAC,MAAM,CAAC,eAAe;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC1E,IAAI,CAAC,MAAM,CAAC,gBAAgB;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAE3E,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAEhC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACzD,QAAQ,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,gBAAgB,GAAG,aAAa,CAAC,CAAC;IAE7E,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,gBAAgB,CAAC,MAA2B;IACnD,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,CAAC,MAAM,CAAC,qBAAqB;QAAE,OAAO,IAAI,CAAC;IAE/E,IAAI,OAAO,MAAM,CAAC,qBAAqB,KAAK,QAAQ,EAAE,CAAC;QACrD,OAAO,MAAM,CAAC,qBAAqB,CAAC;IACtC,CAAC;IAED,QAAQ,MAAM,CAAC,qBAAqB,EAAE,CAAC;QACrC,KAAK,SAAS;YACZ,OAAO,IAAI,mBAAmB,EAAE,CAAC;QACnC,KAAK,WAAW;YACd,OAAO,IAAI,iBAAiB,CAAC;gBAC3B,GAAG,EAAE,8BAA8B;gBACnC,WAAW,EAAE,WAAW,CAAC,SAAS,EAAE;gBACpC,QAAQ,EAAE,oBAAoB,CAAC,MAAM,CAAC;aACvC,CAAC,CAAC;QACL,KAAK,QAAQ;YACX,OAAO,IAAI,qBAAqB,EAAE,CAAC;QACrC;YACE,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACvF,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,MAA2B;IACpD,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,CAAC,MAAM,CAAC,2BAA2B;QAAE,OAAO,IAAI,CAAC;IAErF,IAAI,OAAO,MAAM,CAAC,2BAA2B,KAAK,QAAQ,EAAE,CAAC;QAC3D,OAAO,MAAM,CAAC,2BAA2B,CAAC;IAC5C,CAAC;IAED,QAAQ,MAAM,CAAC,2BAA2B,EAAE,CAAC;QAC3C,KAAK,SAAS;YACZ,OAAO,IAAI,qBAAqB,EAAE,CAAC;QACrC,KAAK,WAAW;YACd,OAAO,IAAI,kBAAkB,CAAC;gBAC5B,GAAG,EAAE,8BAA8B;gBACnC,WAAW,EAAE,WAAW,CAAC,SAAS,EAAE;gBACpC,sEAAsE;gBACtE,oEAAoE;gBACpE,QAAQ,EAAE,oBAAoB,CAAC,MAAM,EAAE,UAAU,CAAC;gBAClD,sEAAsE;gBACtE,mEAAmE;gBACnE,+DAA+D;gBAC/D,qBAAqB,EAAE,sBAAsB,CAAC,KAAK;aACpD,CAAC,CAAC;QACL;YACE,MAAM,IAAI,KAAK,CACb,0CAA0C,MAAM,CAAC,2BAA2B,EAAE,CAC/E,CAAC;IACN,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,MAA2B;IACnD,IAAI,CAAC,MAAM,CAAC,oBAAoB;QAAE,OAAO,IAAI,iBAAiB,EAAE,CAAC;IAEjE,IAAI,OAAO,MAAM,CAAC,0BAA0B,KAAK,QAAQ,EAAE,CAAC;QAC1D,OAAO,MAAM,CAAC,0BAA0B,CAAC;IAC3C,CAAC;IAED,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,iBAAiB,EAAE,CAAC;IAEnD,QAAQ,MAAM,CAAC,0BAA0B,IAAI,OAAO,EAAE,CAAC;QACrD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,OAAO,IAAI,wBAAwB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,CAAC,0BAA0B,EAAE,CAAC,CAAC;QAChG,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAA2B;IAC7C,IAAI,CAAC,MAAM,CAAC,oBAAoB;QAAE,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAEhE,QAAQ,MAAM,CAAC,wBAAwB,IAAI,WAAW,EAAE,CAAC;QACvD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,OAAO,IAAI,eAAe,EAAE,CAAC;QAC/B,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,OAAO,IAAI,gBAAgB,EAAE,CAAC;QAChC,CAAC;QACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,OAAO,IAAI,kBAAkB,CAAC;gBAC5B,IAAI,EAAE,IAAI,wBAAwB,CAAC,MAAM,CAAC,uBAAuB,CAAC;aACnE,CAAC,CAAC;QACL,CAAC;QACD;YACE,MAAM,IAAI,KAAK,CAAC,uCAAuC,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC;IAC9F,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,MAA2B;IACpD,MAAM,cAAc,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEnC,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,6EAA6E;IAC7E,0DAA0D;IAE1D,IAAI,QAAQ,GAAG,eAAe,CAAC;QAC7B,0EAA0E;QAC1E,iFAAiF;QACjF,gFAAgF;QAChF,8EAA8E;QAC9E,iFAAiF;QACjF,mFAAmF;QACnF,wCAAwC;QACxC,EAAE;QACF,iFAAiF;QACjF,iFAAiF;QACjF,0DAA0D;QAC1D,SAAS,EAAE;YACT,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI;YAC7D,eAAe;YACf,WAAW;SACZ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KACrB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACjG,CAAC;IAED,kCAAkC;IAClC,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,CAAC;QAChD,OAAO;QACP,QAAQ;QACR,cAAc,EAAE,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KACnD,CAAC,CAAC;IACH,kBAAkB,CAAC,QAAQ,CAAC;QAC1B,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC,CAAC;IACH,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAEzE,kDAAkD;IAClD,cAAc,GAAG,kBAAkB,CAAC;IAEpC,kDAAkD;IAClD,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC;YACtC,QAAQ;YACR,OAAO,EAAE;gBACP,IAAI,6BAA6B,CAAC;oBAChC,QAAQ,EAAE,cAAc;oBACxB,oBAAoB,EAAE,MAAM,CAAC,uCAAuC,IAAI,MAAM;iBAC/E,CAAC;aACH;SACF,CAAC,CAAC;QACH,OAAO,CAAC,sBAAsB,CAAC,aAAa,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,cAAc,CAAC,QAAQ,EAAE,CAAC;QAChC,cAAc,GAAG,IAAI,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["import { Metadata, credentials } from '@grpc/grpc-js';\nimport { type ContextManager, metrics } from '@opentelemetry/api';\nimport { hrTimeToMilliseconds } from '@opentelemetry/core';\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';\nimport { OTLPTraceExporter as OTLPTraceExporterHttp } from '@opentelemetry/exporter-trace-otlp-http';\nimport { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk';\nimport { ConnectInstrumentation } from '@opentelemetry/instrumentation-connect';\nimport { DnsInstrumentation } from '@opentelemetry/instrumentation-dns';\nimport { ExpressInstrumentation, ExpressLayerType } from '@opentelemetry/instrumentation-express';\nimport { HttpInstrumentation } from '@opentelemetry/instrumentation-http';\nimport { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';\nimport { PgInstrumentation } from '@opentelemetry/instrumentation-pg';\nimport { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';\nimport { awsEc2Detector } from '@opentelemetry/resource-detector-aws';\nimport {\n detectResources,\n envDetector,\n processDetector,\n resourceFromAttributes,\n} from '@opentelemetry/resources';\nimport {\n AggregationTemporality,\n ConsoleMetricExporter,\n MeterProvider,\n PeriodicExportingMetricReader,\n type PushMetricExporter,\n} from '@opentelemetry/sdk-metrics';\nimport {\n AlwaysOffSampler,\n AlwaysOnSampler,\n BatchSpanProcessor,\n ConsoleSpanExporter,\n NoopSpanProcessor,\n ParentBasedSampler,\n type ReadableSpan,\n type Sampler,\n SimpleSpanProcessor,\n type SpanExporter,\n type SpanProcessor,\n TraceIdRatioBasedSampler,\n} from '@opentelemetry/sdk-trace-base';\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';\n\n/**\n * Extends `BatchSpanProcessor` to give it the ability to filter out spans\n * before they're queued up to send. This enhances our sampling process so\n * that we can filter spans _after_ they've been emitted.\n */\nclass FilterBatchSpanProcessor extends BatchSpanProcessor {\n private filter: (span: ReadableSpan) => boolean;\n\n constructor(exporter: SpanExporter, filter: (span: ReadableSpan) => boolean) {\n super(exporter);\n this.filter = filter;\n }\n\n /**\n * This is invoked after a span is \"finalized\". `super.onEnd` will queue up\n * the span to be exported, but if we don't call that, we can just drop the\n * span and the parent will be none the wiser!\n */\n onEnd(span: ReadableSpan) {\n if (!this.filter(span)) return;\n\n super.onEnd(span);\n }\n}\n\n/**\n * This will be used with our {@link FilterBatchSpanProcessor} to filter out\n * events that we're not interested in. This helps reduce our event volume\n * but still gives us fine-grained control over which events we keep.\n */\nfunction filter(span: ReadableSpan) {\n if (span.name === 'pg-pool.connect') {\n // Looking at historical data, this generally happens in under a millisecond,\n // precisely because we maintain a pool of long-lived connections. The only\n // time obtaining a client should take longer than that is if we're\n // establishing a connection for the first time, which should happen only at\n // bootup, or if a connection errors out. Those are the cases we're\n // interested in, so we'll filter accordingly.\n return hrTimeToMilliseconds(span.duration) > 1;\n }\n\n // Always return true so that we default to including a span.\n return true;\n}\n\n// When adding new instrumentation here, add the corresponding packages to\n// `commonjs-preloads.ts` so that we can ensure that they're loaded via CJS\n// before anything tries to load them via CJS. This is necessary because the\n// instrumentations can't hook into the ESM loader.\nconst instrumentations = [\n new AwsInstrumentation(),\n new ConnectInstrumentation(),\n new DnsInstrumentation(),\n new ExpressInstrumentation({\n // We use a lot of middleware; it makes the traces way too noisy. If we\n // want telemetry on a particular middleware, we should instrument it\n // manually.\n ignoreLayersType: [ExpressLayerType.MIDDLEWARE],\n ignoreLayers: [\n // These don't provide useful information to us.\n 'router - /',\n 'request handler - /*',\n ],\n }),\n new HttpInstrumentation({\n ignoreIncomingRequestHook(req) {\n return [\n // socket.io requests are generally just long-polling; they don't add\n // useful information for us.\n /\\/socket.io\\//,\n // We get several of these per second; they just chew through our event quota.\n // They don't really do anything interesting anyways.\n /\\/pl\\/webhooks\\/ping/,\n ].some((re) => re.test(req.url ?? '/'));\n },\n }),\n new IORedisInstrumentation(),\n new PgInstrumentation(),\n new RedisInstrumentation(),\n];\n\n// Enable all instrumentations now, even though we haven't configured our\n// span processors or trace exporters yet. We'll set those up later.\ninstrumentations.forEach((i) => {\n i.enable();\n});\n\nlet tracerProvider: NodeTracerProvider | null;\n\ninterface OpenTelemetryConfigEnabled {\n openTelemetryEnabled: boolean;\n openTelemetryExporter?: 'console' | 'honeycomb' | 'jaeger' | SpanExporter | null;\n openTelemetryMetricExporter?: 'console' | 'honeycomb' | PushMetricExporter | null;\n openTelemetryMetricExportIntervalMillis?: number;\n openTelemetrySamplerType: 'always-on' | 'always-off' | 'trace-id-ratio';\n openTelemetrySampleRate?: number;\n openTelemetrySpanProcessor?: 'batch' | 'simple' | SpanProcessor;\n contextManager?: ContextManager;\n honeycombApiKey?: string | null;\n honeycombDataset?: string | null;\n serviceName?: string;\n}\n\n// When we know for sure that OpenTelemetry is disabled, we won't require\n// any other attributes to be set.\ninterface OpenTelemetryConfigDisabled extends Partial<OpenTelemetryConfigEnabled> {\n openTelemetryEnabled: false;\n}\n\nexport type OpenTelemetryConfig = OpenTelemetryConfigEnabled | OpenTelemetryConfigDisabled;\n\nfunction getHoneycombMetadata(config: OpenTelemetryConfig, datasetSuffix = ''): Metadata {\n if (!config.honeycombApiKey) throw new Error('Missing Honeycomb API key');\n if (!config.honeycombDataset) throw new Error('Missing Honeycomb dataset');\n\n const metadata = new Metadata();\n\n metadata.set('x-honeycomb-team', config.honeycombApiKey);\n metadata.set('x-honeycomb-dataset', config.honeycombDataset + datasetSuffix);\n\n return metadata;\n}\n\nfunction getTraceExporter(config: OpenTelemetryConfig): SpanExporter | null {\n if (!config.openTelemetryEnabled || !config.openTelemetryExporter) return null;\n\n if (typeof config.openTelemetryExporter === 'object') {\n return config.openTelemetryExporter;\n }\n\n switch (config.openTelemetryExporter) {\n case 'console':\n return new ConsoleSpanExporter();\n case 'honeycomb':\n return new OTLPTraceExporter({\n url: 'grpc://api.honeycomb.io:443/',\n credentials: credentials.createSsl(),\n metadata: getHoneycombMetadata(config),\n });\n case 'jaeger':\n return new OTLPTraceExporterHttp();\n default:\n throw new Error(`Unknown OpenTelemetry exporter: ${config.openTelemetryExporter}`);\n }\n}\n\nfunction getMetricExporter(config: OpenTelemetryConfig): PushMetricExporter | null {\n if (!config.openTelemetryEnabled || !config.openTelemetryMetricExporter) return null;\n\n if (typeof config.openTelemetryMetricExporter === 'object') {\n return config.openTelemetryMetricExporter;\n }\n\n switch (config.openTelemetryMetricExporter) {\n case 'console':\n return new ConsoleMetricExporter();\n case 'honeycomb':\n return new OTLPMetricExporter({\n url: 'grpc://api.honeycomb.io:443/',\n credentials: credentials.createSsl(),\n // Honeycomb recommends using a separate dataset for metrics, so we'll\n // adopt the convention of appending '-metrics' to the dataset name.\n metadata: getHoneycombMetadata(config, '-metrics'),\n // Delta temporality means that sums, histograms, etc. will reset each\n // time data is collected. This more closely matches how we want to\n // observe our metrics than the default cumulative temporality.\n temporalityPreference: AggregationTemporality.DELTA,\n });\n default:\n throw new Error(\n `Unknown OpenTelemetry metric exporter: ${config.openTelemetryMetricExporter}`,\n );\n }\n}\n\nfunction getSpanProcessor(config: OpenTelemetryConfig): SpanProcessor | null {\n if (!config.openTelemetryEnabled) return new NoopSpanProcessor();\n\n if (typeof config.openTelemetrySpanProcessor === 'object') {\n return config.openTelemetrySpanProcessor;\n }\n\n const traceExporter = getTraceExporter(config);\n if (!traceExporter) return new NoopSpanProcessor();\n\n switch (config.openTelemetrySpanProcessor ?? 'batch') {\n case 'batch': {\n return new FilterBatchSpanProcessor(traceExporter, filter);\n }\n case 'simple': {\n return new SimpleSpanProcessor(traceExporter);\n }\n default: {\n throw new Error(`Unknown OpenTelemetry span processor: ${config.openTelemetrySpanProcessor}`);\n }\n }\n}\n\nfunction getSampler(config: OpenTelemetryConfig): Sampler {\n if (!config.openTelemetryEnabled) return new AlwaysOffSampler();\n\n switch (config.openTelemetrySamplerType ?? 'always-on') {\n case 'always-on': {\n return new AlwaysOnSampler();\n }\n case 'always-off': {\n return new AlwaysOffSampler();\n }\n case 'trace-id-ratio': {\n return new ParentBasedSampler({\n root: new TraceIdRatioBasedSampler(config.openTelemetrySampleRate),\n });\n }\n default:\n throw new Error(`Unknown OpenTelemetry sampler type: ${config.openTelemetrySamplerType}`);\n }\n}\n\n/**\n * Should be called once we've loaded our config; this will allow us to set up\n * the correct metadata for the Honeycomb exporter. We don't actually have that\n * information available until we've loaded our config.\n *\n * Note that even when `openTelemetryEnabled` is `false`, we'll still configure\n * the `NodeTraceProvider` and instrumentations, as Sentry relies on that for\n * scope isolation. However, we won't actually set up any exporters.\n */\nexport async function init(config: OpenTelemetryConfig) {\n const metricExporter = getMetricExporter(config);\n const spanProcessor = getSpanProcessor(config);\n const sampler = getSampler(config);\n\n // Much of this functionality is copied from `@opentelemetry/sdk-node`, but\n // we can't use the SDK directly because of the fact that we load our config\n // asynchronously. We need to initialize our instrumentations first; only\n // then can we actually start requiring all of our code that loads our config\n // and ultimately tells us how to configure OpenTelemetry.\n\n let resource = detectResources({\n // The AWS resource detector always tries to reach out to the EC2 metadata\n // service endpoint. When running locally, or otherwise in a non-AWS environment,\n // this will typically fail immediately wih `EHOSTDOWN`, but will sometimes wait\n // 5 seconds before failing with a network timeout error. This causes problems\n // when running tests, as 5 seconds is longer than Mocha lets tests and hooks run\n // for by default. This causes nondeterministic test failures when the EC2 metadata\n // request fails with a network timeout.\n //\n // To work around this, the AWS resource detector is only enabled when running in\n // a production environment. In general this is reasonable, as we only care about\n // AWS resource detection in production-like environments.\n detectors: [\n process.env.NODE_ENV === 'production' ? awsEc2Detector : null,\n processDetector,\n envDetector,\n ].filter((d) => !!d),\n });\n\n if (config.serviceName) {\n resource = resource.merge(resourceFromAttributes({ [ATTR_SERVICE_NAME]: config.serviceName }));\n }\n\n // Set up tracing instrumentation.\n const nodeTracerProvider = new NodeTracerProvider({\n sampler,\n resource,\n spanProcessors: [spanProcessor].filter((p) => !!p),\n });\n nodeTracerProvider.register({\n contextManager: config.contextManager,\n });\n instrumentations.forEach((i) => i.setTracerProvider(nodeTracerProvider));\n\n // Save the provider so we can shut it down later.\n tracerProvider = nodeTracerProvider;\n\n // Set up metrics instrumentation if it's enabled.\n if (metricExporter) {\n const meterProvider = new MeterProvider({\n resource,\n readers: [\n new PeriodicExportingMetricReader({\n exporter: metricExporter,\n exportIntervalMillis: config.openTelemetryMetricExportIntervalMillis ?? 30_000,\n }),\n ],\n });\n metrics.setGlobalMeterProvider(meterProvider);\n }\n}\n\n/**\n * Gracefully shuts down the OpenTelemetry instrumentation. Should be called\n * when a `SIGTERM` signal is handled.\n */\nexport async function shutdown(): Promise<void> {\n if (tracerProvider) {\n await tracerProvider.shutdown();\n tracerProvider = null;\n }\n}\n\n/**\n * Disables all OpenTelemetry instrumentations. This is useful for tests that\n * need to access the unwrapped modules.\n */\nexport function disableInstrumentations() {\n instrumentations.forEach((i) => i.disable());\n}\n"]}
|
package/dist/metrics.test.js
CHANGED
|
@@ -9,21 +9,22 @@ async function waitForMetricsExport(exporter) {
|
|
|
9
9
|
}
|
|
10
10
|
describe('instrumentedWithMetrics', () => {
|
|
11
11
|
let exporter;
|
|
12
|
-
let
|
|
12
|
+
let meterProvider;
|
|
13
13
|
let meter;
|
|
14
14
|
beforeEach(async () => {
|
|
15
|
-
const meterProvider = new MeterProvider();
|
|
16
|
-
meter = meterProvider.getMeter('test');
|
|
17
15
|
exporter = new InMemoryMetricExporter(AggregationTemporality.DELTA);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
meterProvider = new MeterProvider({
|
|
17
|
+
readers: [
|
|
18
|
+
new PeriodicExportingMetricReader({
|
|
19
|
+
exporter,
|
|
20
|
+
exportIntervalMillis: 50,
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
21
23
|
});
|
|
22
|
-
meterProvider.
|
|
24
|
+
meter = meterProvider.getMeter('test');
|
|
23
25
|
});
|
|
24
26
|
afterEach(async () => {
|
|
25
|
-
await
|
|
26
|
-
await metricReader.shutdown();
|
|
27
|
+
await meterProvider.shutdown();
|
|
27
28
|
});
|
|
28
29
|
it('records a histogram for the function duration', async () => {
|
|
29
30
|
await instrumentedWithMetrics(meter, 'test', async () => { });
|
package/dist/metrics.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.test.js","sourceRoot":"","sources":["../src/metrics.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,sBAAsB,EAEtB,sBAAsB,EACtB,aAAa,EACb,6BAA6B,GAC9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,KAAK,UAAU,oBAAoB,CAAC,QAAgC;IAClE,OAAO,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,QAAgC,CAAC;IACrC,IAAI,
|
|
1
|
+
{"version":3,"file":"metrics.test.js","sourceRoot":"","sources":["../src/metrics.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Meter } from '@opentelemetry/api';\nimport {\n AggregationTemporality,\n type Histogram,\n InMemoryMetricExporter,\n MeterProvider,\n PeriodicExportingMetricReader,\n} from '@opentelemetry/sdk-metrics';\nimport { afterEach, assert, beforeEach, describe, expect, it } from 'vitest';\n\nimport { instrumentedWithMetrics } from './metrics.js';\n\nasync function waitForMetricsExport(exporter: InMemoryMetricExporter) {\n while (exporter.getMetrics().length === 0) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n}\n\ndescribe('instrumentedWithMetrics', () => {\n let exporter: InMemoryMetricExporter;\n let meterProvider: MeterProvider;\n let meter: Meter;\n\n beforeEach(async () => {\n exporter = new InMemoryMetricExporter(AggregationTemporality.DELTA);\n meterProvider = new MeterProvider({\n readers: [\n new PeriodicExportingMetricReader({\n exporter,\n exportIntervalMillis: 50,\n }),\n ],\n });\n meter = meterProvider.getMeter('test');\n });\n\n afterEach(async () => {\n await meterProvider.shutdown();\n });\n\n it('records a histogram for the function duration', async () => {\n await instrumentedWithMetrics(meter, 'test', async () => {});\n\n await waitForMetricsExport(exporter);\n const exportedMetrics = exporter.getMetrics();\n const { scope, metrics } = exportedMetrics[0].scopeMetrics[0];\n\n // We won't see an exported metric for the error counter because the\n // Metrics SDK no longer exports metrics with no data points.\n // https://github.com/open-telemetry/opentelemetry-js/pull/4135\n assert.lengthOf(metrics, 1);\n const [histogramMetric] = metrics;\n\n assert.equal(scope.name, 'test');\n\n assert.ok(histogramMetric);\n assert.equal(histogramMetric.descriptor.name, 'test.duration');\n assert.equal((histogramMetric.dataPoints[0].value as Histogram).count, 1);\n });\n\n it('records an error count', async () => {\n await expect(\n instrumentedWithMetrics(meter, 'test', async () => {\n throw new Error('error for test');\n }),\n ).rejects.toThrow('error for test');\n\n await waitForMetricsExport(exporter);\n const exportedMetrics = exporter.getMetrics();\n const { metrics, scope } = exportedMetrics[0].scopeMetrics[0];\n\n // An error was reported above, so there will be both the error counter\n // and histogram metrics.\n assert.lengthOf(metrics, 2);\n const [counterMetric, histogramMetric] = metrics;\n\n assert.ok(scope);\n assert.equal(scope.name, 'test');\n\n assert.ok(counterMetric);\n assert.equal(counterMetric.descriptor.name, 'test.error');\n assert.equal(counterMetric.dataPoints[0].value, 1);\n\n assert.ok(histogramMetric);\n assert.equal(histogramMetric.descriptor.name, 'test.duration');\n assert.equal((histogramMetric.dataPoints[0].value as Histogram).count, 1);\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/opentelemetry",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,34 +16,34 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@grpc/grpc-js": "^1.13.4",
|
|
18
18
|
"@opentelemetry/api": "^1.9.0",
|
|
19
|
-
"@opentelemetry/core": "^
|
|
20
|
-
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.
|
|
21
|
-
"@opentelemetry/exporter-trace-otlp-grpc": "^0.
|
|
22
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.
|
|
23
|
-
"@opentelemetry/instrumentation": "^0.
|
|
24
|
-
"@opentelemetry/instrumentation-aws-sdk": "^0.
|
|
25
|
-
"@opentelemetry/instrumentation-connect": "^0.
|
|
26
|
-
"@opentelemetry/instrumentation-dns": "^0.
|
|
27
|
-
"@opentelemetry/instrumentation-express": "^0.
|
|
28
|
-
"@opentelemetry/instrumentation-http": "^0.
|
|
29
|
-
"@opentelemetry/instrumentation-ioredis": "^0.
|
|
30
|
-
"@opentelemetry/instrumentation-pg": "^0.
|
|
31
|
-
"@opentelemetry/instrumentation-redis": "^0.
|
|
32
|
-
"@opentelemetry/resource-detector-aws": "^
|
|
33
|
-
"@opentelemetry/resources": "^
|
|
34
|
-
"@opentelemetry/sdk-metrics": "^
|
|
35
|
-
"@opentelemetry/sdk-node": "^0.
|
|
36
|
-
"@opentelemetry/sdk-trace-base": "^
|
|
37
|
-
"@opentelemetry/sdk-trace-node": "^
|
|
38
|
-
"@opentelemetry/semantic-conventions": "^1.
|
|
19
|
+
"@opentelemetry/core": "^2.0.1",
|
|
20
|
+
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.203.0",
|
|
21
|
+
"@opentelemetry/exporter-trace-otlp-grpc": "^0.203.0",
|
|
22
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.203.0",
|
|
23
|
+
"@opentelemetry/instrumentation": "^0.203.0",
|
|
24
|
+
"@opentelemetry/instrumentation-aws-sdk": "^0.56.0",
|
|
25
|
+
"@opentelemetry/instrumentation-connect": "^0.47.0",
|
|
26
|
+
"@opentelemetry/instrumentation-dns": "^0.47.0",
|
|
27
|
+
"@opentelemetry/instrumentation-express": "^0.52.0",
|
|
28
|
+
"@opentelemetry/instrumentation-http": "^0.203.0",
|
|
29
|
+
"@opentelemetry/instrumentation-ioredis": "^0.51.0",
|
|
30
|
+
"@opentelemetry/instrumentation-pg": "^0.55.0",
|
|
31
|
+
"@opentelemetry/instrumentation-redis": "^0.51.0",
|
|
32
|
+
"@opentelemetry/resource-detector-aws": "^2.3.0",
|
|
33
|
+
"@opentelemetry/resources": "^2.0.1",
|
|
34
|
+
"@opentelemetry/sdk-metrics": "^2.0.1",
|
|
35
|
+
"@opentelemetry/sdk-node": "^0.203.0",
|
|
36
|
+
"@opentelemetry/sdk-trace-base": "^2.0.1",
|
|
37
|
+
"@opentelemetry/sdk-trace-node": "^2.0.1",
|
|
38
|
+
"@opentelemetry/semantic-conventions": "^1.36.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@opentelemetry/context-async-hooks": "^
|
|
41
|
+
"@opentelemetry/context-async-hooks": "^2.0.1",
|
|
42
42
|
"@prairielearn/tsconfig": "^0.0.0",
|
|
43
|
-
"@types/node": "^22.
|
|
43
|
+
"@types/node": "^22.17.0",
|
|
44
44
|
"@vitest/coverage-v8": "^3.2.4",
|
|
45
45
|
"tsx": "^4.20.3",
|
|
46
|
-
"typescript": "^5.
|
|
46
|
+
"typescript": "^5.9.2",
|
|
47
47
|
"vitest": "^3.2.4"
|
|
48
48
|
}
|
|
49
49
|
}
|
package/src/init.ts
CHANGED
|
@@ -14,10 +14,10 @@ import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
|
|
|
14
14
|
import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';
|
|
15
15
|
import { awsEc2Detector } from '@opentelemetry/resource-detector-aws';
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
detectResourcesSync,
|
|
17
|
+
detectResources,
|
|
19
18
|
envDetector,
|
|
20
19
|
processDetector,
|
|
20
|
+
resourceFromAttributes,
|
|
21
21
|
} from '@opentelemetry/resources';
|
|
22
22
|
import {
|
|
23
23
|
AggregationTemporality,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
AlwaysOnSampler,
|
|
32
32
|
BatchSpanProcessor,
|
|
33
33
|
ConsoleSpanExporter,
|
|
34
|
+
NoopSpanProcessor,
|
|
34
35
|
ParentBasedSampler,
|
|
35
36
|
type ReadableSpan,
|
|
36
37
|
type Sampler,
|
|
@@ -40,7 +41,7 @@ import {
|
|
|
40
41
|
TraceIdRatioBasedSampler,
|
|
41
42
|
} from '@opentelemetry/sdk-trace-base';
|
|
42
43
|
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
|
43
|
-
import {
|
|
44
|
+
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* Extends `BatchSpanProcessor` to give it the ability to filter out spans
|
|
@@ -166,7 +167,7 @@ function getHoneycombMetadata(config: OpenTelemetryConfig, datasetSuffix = ''):
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
function getTraceExporter(config: OpenTelemetryConfig): SpanExporter | null {
|
|
169
|
-
if (!config.openTelemetryExporter) return null;
|
|
170
|
+
if (!config.openTelemetryEnabled || !config.openTelemetryExporter) return null;
|
|
170
171
|
|
|
171
172
|
if (typeof config.openTelemetryExporter === 'object') {
|
|
172
173
|
return config.openTelemetryExporter;
|
|
@@ -189,7 +190,7 @@ function getTraceExporter(config: OpenTelemetryConfig): SpanExporter | null {
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
function getMetricExporter(config: OpenTelemetryConfig): PushMetricExporter | null {
|
|
192
|
-
if (!config.openTelemetryMetricExporter) return null;
|
|
193
|
+
if (!config.openTelemetryEnabled || !config.openTelemetryMetricExporter) return null;
|
|
193
194
|
|
|
194
195
|
if (typeof config.openTelemetryMetricExporter === 'object') {
|
|
195
196
|
return config.openTelemetryMetricExporter;
|
|
@@ -218,12 +219,14 @@ function getMetricExporter(config: OpenTelemetryConfig): PushMetricExporter | nu
|
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
function getSpanProcessor(config: OpenTelemetryConfig): SpanProcessor | null {
|
|
222
|
+
if (!config.openTelemetryEnabled) return new NoopSpanProcessor();
|
|
223
|
+
|
|
221
224
|
if (typeof config.openTelemetrySpanProcessor === 'object') {
|
|
222
225
|
return config.openTelemetrySpanProcessor;
|
|
223
226
|
}
|
|
224
227
|
|
|
225
228
|
const traceExporter = getTraceExporter(config);
|
|
226
|
-
if (!traceExporter) return
|
|
229
|
+
if (!traceExporter) return new NoopSpanProcessor();
|
|
227
230
|
|
|
228
231
|
switch (config.openTelemetrySpanProcessor ?? 'batch') {
|
|
229
232
|
case 'batch': {
|
|
@@ -238,45 +241,39 @@ function getSpanProcessor(config: OpenTelemetryConfig): SpanProcessor | null {
|
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
243
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
* the correct metadata for the Honeycomb exporter. We don't actually have that
|
|
244
|
-
* information available until we've loaded our config.
|
|
245
|
-
*/
|
|
246
|
-
export async function init(config: OpenTelemetryConfig) {
|
|
247
|
-
if (!config.openTelemetryEnabled) {
|
|
248
|
-
// If not enabled, do nothing. We used to disable the instrumentations, but
|
|
249
|
-
// per maintainers, that can actually be problematic. See the comments on
|
|
250
|
-
// https://github.com/open-telemetry/opentelemetry-js-contrib/issues/970
|
|
251
|
-
// The Express instrumentation also logs a benign error, which can be
|
|
252
|
-
// confusing to users. There's a fix in progress if we want to switch back
|
|
253
|
-
// to disabling instrumentations in the future:
|
|
254
|
-
// https://github.com/open-telemetry/opentelemetry-js-contrib/pull/972
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const metricExporter = getMetricExporter(config);
|
|
259
|
-
const spanProcessor = getSpanProcessor(config);
|
|
244
|
+
function getSampler(config: OpenTelemetryConfig): Sampler {
|
|
245
|
+
if (!config.openTelemetryEnabled) return new AlwaysOffSampler();
|
|
260
246
|
|
|
261
|
-
let sampler: Sampler;
|
|
262
247
|
switch (config.openTelemetrySamplerType ?? 'always-on') {
|
|
263
248
|
case 'always-on': {
|
|
264
|
-
|
|
265
|
-
break;
|
|
249
|
+
return new AlwaysOnSampler();
|
|
266
250
|
}
|
|
267
251
|
case 'always-off': {
|
|
268
|
-
|
|
269
|
-
break;
|
|
252
|
+
return new AlwaysOffSampler();
|
|
270
253
|
}
|
|
271
254
|
case 'trace-id-ratio': {
|
|
272
|
-
|
|
255
|
+
return new ParentBasedSampler({
|
|
273
256
|
root: new TraceIdRatioBasedSampler(config.openTelemetrySampleRate),
|
|
274
257
|
});
|
|
275
|
-
break;
|
|
276
258
|
}
|
|
277
259
|
default:
|
|
278
260
|
throw new Error(`Unknown OpenTelemetry sampler type: ${config.openTelemetrySamplerType}`);
|
|
279
261
|
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Should be called once we've loaded our config; this will allow us to set up
|
|
266
|
+
* the correct metadata for the Honeycomb exporter. We don't actually have that
|
|
267
|
+
* information available until we've loaded our config.
|
|
268
|
+
*
|
|
269
|
+
* Note that even when `openTelemetryEnabled` is `false`, we'll still configure
|
|
270
|
+
* the `NodeTraceProvider` and instrumentations, as Sentry relies on that for
|
|
271
|
+
* scope isolation. However, we won't actually set up any exporters.
|
|
272
|
+
*/
|
|
273
|
+
export async function init(config: OpenTelemetryConfig) {
|
|
274
|
+
const metricExporter = getMetricExporter(config);
|
|
275
|
+
const spanProcessor = getSpanProcessor(config);
|
|
276
|
+
const sampler = getSampler(config);
|
|
280
277
|
|
|
281
278
|
// Much of this functionality is copied from `@opentelemetry/sdk-node`, but
|
|
282
279
|
// we can't use the SDK directly because of the fact that we load our config
|
|
@@ -284,7 +281,7 @@ export async function init(config: OpenTelemetryConfig) {
|
|
|
284
281
|
// then can we actually start requiring all of our code that loads our config
|
|
285
282
|
// and ultimately tells us how to configure OpenTelemetry.
|
|
286
283
|
|
|
287
|
-
let resource =
|
|
284
|
+
let resource = detectResources({
|
|
288
285
|
// The AWS resource detector always tries to reach out to the EC2 metadata
|
|
289
286
|
// service endpoint. When running locally, or otherwise in a non-AWS environment,
|
|
290
287
|
// this will typically fail immediately wih `EHOSTDOWN`, but will sometimes wait
|
|
@@ -304,19 +301,15 @@ export async function init(config: OpenTelemetryConfig) {
|
|
|
304
301
|
});
|
|
305
302
|
|
|
306
303
|
if (config.serviceName) {
|
|
307
|
-
resource = resource.merge(
|
|
308
|
-
new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: config.serviceName }),
|
|
309
|
-
);
|
|
304
|
+
resource = resource.merge(resourceFromAttributes({ [ATTR_SERVICE_NAME]: config.serviceName }));
|
|
310
305
|
}
|
|
311
306
|
|
|
312
307
|
// Set up tracing instrumentation.
|
|
313
308
|
const nodeTracerProvider = new NodeTracerProvider({
|
|
314
309
|
sampler,
|
|
315
310
|
resource,
|
|
311
|
+
spanProcessors: [spanProcessor].filter((p) => !!p),
|
|
316
312
|
});
|
|
317
|
-
if (spanProcessor) {
|
|
318
|
-
nodeTracerProvider.addSpanProcessor(spanProcessor);
|
|
319
|
-
}
|
|
320
313
|
nodeTracerProvider.register({
|
|
321
314
|
contextManager: config.contextManager,
|
|
322
315
|
});
|
package/src/metrics.test.ts
CHANGED
|
@@ -18,23 +18,24 @@ async function waitForMetricsExport(exporter: InMemoryMetricExporter) {
|
|
|
18
18
|
|
|
19
19
|
describe('instrumentedWithMetrics', () => {
|
|
20
20
|
let exporter: InMemoryMetricExporter;
|
|
21
|
-
let
|
|
21
|
+
let meterProvider: MeterProvider;
|
|
22
22
|
let meter: Meter;
|
|
23
23
|
|
|
24
24
|
beforeEach(async () => {
|
|
25
|
-
const meterProvider = new MeterProvider();
|
|
26
|
-
meter = meterProvider.getMeter('test');
|
|
27
25
|
exporter = new InMemoryMetricExporter(AggregationTemporality.DELTA);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
meterProvider = new MeterProvider({
|
|
27
|
+
readers: [
|
|
28
|
+
new PeriodicExportingMetricReader({
|
|
29
|
+
exporter,
|
|
30
|
+
exportIntervalMillis: 50,
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
31
33
|
});
|
|
32
|
-
meterProvider.
|
|
34
|
+
meter = meterProvider.getMeter('test');
|
|
33
35
|
});
|
|
34
36
|
|
|
35
37
|
afterEach(async () => {
|
|
36
|
-
await
|
|
37
|
-
await metricReader.shutdown();
|
|
38
|
+
await meterProvider.shutdown();
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
it('records a histogram for the function duration', async () => {
|