From 42ed8c51cce257bf14ead835b7ca377f640e2b80 Mon Sep 17 00:00:00 2001
From: Rowan Manning <138944+rowanmanning@users.noreply.github.com>
Date: Wed, 11 Mar 2026 13:46:22 +0000
Subject: [PATCH] refactor!: migrate opentelemetry to ESM
This involves a bit of a refactor because we can no longer clear the
module cache. Once again it results in more sensible code and better
tests :+1:
---
packages/opentelemetry/README.md | 26 +--
.../lib/config/instrumentations.js | 10 +-
packages/opentelemetry/lib/config/metrics.js | 16 +-
packages/opentelemetry/lib/config/resource.js | 15 +-
packages/opentelemetry/lib/config/tracing.js | 13 +-
.../opentelemetry/lib/config/user-agents.js | 16 +-
packages/opentelemetry/lib/config/views.js | 13 +-
packages/opentelemetry/lib/index.js | 37 ++--
packages/opentelemetry/lib/setup-from-env.js | 59 ++++++
packages/opentelemetry/package.json | 1 +
packages/opentelemetry/setup.js | 55 +-----
.../test/end-to-end/fixtures/app.js | 8 +-
.../test/end-to-end/fixtures/collector.js | 4 +-
.../test/end-to-end/index.spec.js | 14 +-
.../unit/lib/config/instrumentations.spec.js | 6 +-
.../test/unit/lib/config/metrics.spec.js | 12 +-
.../test/unit/lib/config/resource.spec.js | 10 +-
.../test/unit/lib/config/tracing.spec.js | 12 +-
.../test/unit/lib/config/user-agents.spec.js | 8 +-
.../test/unit/lib/config/views.spec.js | 14 +-
.../opentelemetry/test/unit/lib/index.spec.js | 157 ++++++---------
.../test/unit/lib/setup-from-env.spec.js | 177 +++++++++++++++++
.../opentelemetry/test/unit/setup.spec.js | 180 ++----------------
23 files changed, 425 insertions(+), 438 deletions(-)
create mode 100644 packages/opentelemetry/lib/setup-from-env.js
create mode 100644 packages/opentelemetry/test/unit/lib/setup-from-env.spec.js
diff --git a/packages/opentelemetry/README.md b/packages/opentelemetry/README.md
index d6edc42f2..194a11108 100644
--- a/packages/opentelemetry/README.md
+++ b/packages/opentelemetry/README.md
@@ -8,8 +8,8 @@ An [OpenTelemetry](https://opentelemetry.io/docs/what-is-opentelemetry/) client
* [Usage](#usage)
* [Setup](#setup)
- * [Automated setup with `--require`](#automated-setup-with---require)
- * [Automated setup with `require()`](#automated-setup-with-require)
+ * [Automated setup with `--import`](#automated-setup-with---import)
+ * [Automated setup with `import`](#automated-setup-with-import)
* [Manual setup](#manual-setup)
* [Sending custom metrics](#sending-custom-metrics)
* [Running in production](#running-in-production)
@@ -59,17 +59,17 @@ npm install --save @dotcom-reliability-kit/opentelemetry
You can set up OpenTelemetry in a number of ways, each has pros and cons which we'll outline in the sections below.
-#### Automated setup with `--require`
+#### Automated setup with `--import`
-You can completely avoid code changes by setting up OpenTelemetry using the Node.js [`--require` command-line option](https://nodejs.org/api/cli.html#-r---require-module):
+You can completely avoid code changes by setting up OpenTelemetry using the Node.js [`--import` command-line option](https://nodejs.org/api/cli.html#importmodule):
```sh
-node --require @dotcom-reliability-kit/opentelemetry/setup ./my-app.js
+node --import @dotcom-reliability-kit/opentelemetry/setup ./my-app.js
```
This will import our setup script _before_ any of your code. OpenTelemetry will be [configured](#configuration-options) with environment variables.
-For environments where you can't modify the `node` command directly (e.g. AWS Lambda) you'll need to specify this using the `NODE_OPTIONS` environment variable set to `--require @dotcom-reliability-kit/opentelemetry/setup`.
+For environments where you can't modify the `node` command directly (e.g. AWS Lambda) you'll need to specify this using the `NODE_OPTIONS` environment variable set to `--import @dotcom-reliability-kit/opentelemetry/setup`.
@@ -86,20 +86,18 @@ For environments where you can't modify the `node` command directly (e.g. AWS La
- - It may be easy to accidentally remove the `--require`
+ - It may be easy to accidentally remove the `--import`
|
-#### Automated setup with `require()`
+#### Automated setup with `import`
-If you can't use `--require`, e.g. because your tooling won't allow it, then you can include the setup script directly in your code:
+If you can't use `--import`, e.g. because your tooling won't allow it, then you can include the setup script directly in your code:
```js
import '@dotcom-reliability-kit/opentelemetry/setup';
-// or
-require('@dotcom-reliability-kit/opentelemetry/setup');
```
OpenTelemetry will be [configured](#configuration-options) with environment variables.
@@ -134,8 +132,6 @@ If you'd like to customise the OpenTelemetry config more and have control over w
```js
import * as opentelemetry from '@dotcom-reliability-kit/opentelemetry';
-// or
-const opentelemetry = require('@dotcom-reliability-kit/opentelemetry');
```
Call the function, passing in [configuration options](#configuration-options):
@@ -178,8 +174,6 @@ In your code, load in the `getMeter` function:
```js
import { getMeter } from '@dotcom-reliability-kit/opentelemetry';
-// or
-const { getMeter } = require('@dotcom-reliability-kit/opentelemetry');
```
You can now use it in the same way as the built-in OpenTelemetry equivalent. For more information, see the [OpenTelemetry Meter documentation](https://opentelemetry.io/docs/specs/otel/metrics/api/#meter).
@@ -249,7 +243,7 @@ Some details about how we're implementing OpenTelemetry. This is to help avoid a
Depending on the way you set up OpenTelemetry, you can either configure it via environment variables or options passed into an object.
-For automated setups ([here](#automated-setup-with---require) and [here](#automated-setup-with-require)) you'll need to use environment variables, e.g.
+For automated setups ([here](#automated-setup-with---import) and [here](#automated-setup-with-import)) you'll need to use environment variables, e.g.
```sh
EXAMPLE=true npm start
diff --git a/packages/opentelemetry/lib/config/instrumentations.js b/packages/opentelemetry/lib/config/instrumentations.js
index a00ff42e6..7aec3b6e1 100644
--- a/packages/opentelemetry/lib/config/instrumentations.js
+++ b/packages/opentelemetry/lib/config/instrumentations.js
@@ -1,6 +1,6 @@
-const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
-const { logRecoverableError } = require('@dotcom-reliability-kit/log-error');
-const { UserInputError } = require('@dotcom-reliability-kit/errors');
+import { UserInputError } from '@dotcom-reliability-kit/errors';
+import { logRecoverableError } from '@dotcom-reliability-kit/log-error';
+import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
/**
* @import { NodeSDKConfiguration } from '@opentelemetry/sdk-node'
@@ -15,7 +15,7 @@ const IGNORED_REQUEST_PATHS = ['/__gtg', '/__health', '/favicon.ico'];
*
* @returns {NodeSDKConfiguration['instrumentations']}
*/
-exports.createInstrumentationConfig = function createInstrumentationConfig() {
+export function createInstrumentationConfig() {
return getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-http': {
ignoreIncomingRequestHook
@@ -24,7 +24,7 @@ exports.createInstrumentationConfig = function createInstrumentationConfig() {
enabled: false
}
});
-};
+}
/**
* NOTE: this is not a filter like you know it. The name gives us a clue:
diff --git a/packages/opentelemetry/lib/config/metrics.js b/packages/opentelemetry/lib/config/metrics.js
index ca594ef0d..8fbd2e6db 100644
--- a/packages/opentelemetry/lib/config/metrics.js
+++ b/packages/opentelemetry/lib/config/metrics.js
@@ -1,8 +1,10 @@
-const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-proto');
-const { CompressionAlgorithm } = require('@opentelemetry/otlp-exporter-base');
-const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-node').metrics;
-const { default: logger } = require('@dotcom-reliability-kit/logger');
-const { METRICS_USER_AGENT } = require('./user-agents');
+import logger from '@dotcom-reliability-kit/logger';
+import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';
+import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base';
+import { metrics } from '@opentelemetry/sdk-node';
+import { METRICS_USER_AGENT } from './user-agents.js';
+
+const { PeriodicExportingMetricReader } = metrics;
/**
* @import { NodeSDKConfiguration } from '@opentelemetry/sdk-node'
@@ -15,7 +17,7 @@ const { METRICS_USER_AGENT } = require('./user-agents');
* @param {MetricsOptions} options
* @returns {Partial}
*/
-exports.createMetricsConfig = function createMetricsConfig(options) {
+export function createMetricsConfig(options) {
/** @type {Partial} */
const config = {};
@@ -53,4 +55,4 @@ exports.createMetricsConfig = function createMetricsConfig(options) {
}
return config;
-};
+}
diff --git a/packages/opentelemetry/lib/config/resource.js b/packages/opentelemetry/lib/config/resource.js
index d003287b7..af88e2054 100644
--- a/packages/opentelemetry/lib/config/resource.js
+++ b/packages/opentelemetry/lib/config/resource.js
@@ -1,10 +1,9 @@
-const appInfo = require('@dotcom-reliability-kit/app-info').semanticConventions;
-const { defaultResource, resourceFromAttributes } = require('@opentelemetry/sdk-node').resources;
-const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions');
+import { semanticConventions as appInfo } from '@dotcom-reliability-kit/app-info';
-/**
- * @import { resources } from '@opentelemetry/sdk-node'
- */
+import { resources } from '@opentelemetry/sdk-node';
+import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
+
+const { defaultResource, resourceFromAttributes } = resources;
// These are hard-coded because they're unstable and OpenTelemetry advices we do this:
// https://github.com/open-telemetry/opentelemetry-js/blob/main/semantic-conventions/README.md#unstable-semconv
@@ -18,7 +17,7 @@ const ATTR_SERVICE_INSTANCE_ID = 'service.instance.id';
*
* @returns {resources.Resource}
*/
-exports.createResourceConfig = function createResourceConfig() {
+export function createResourceConfig() {
// We set OpenTelemetry resource attributes based on app data
return defaultResource().merge(
resourceFromAttributes({
@@ -30,4 +29,4 @@ exports.createResourceConfig = function createResourceConfig() {
[ATTR_DEPLOYMENT_ENVIRONMENT]: appInfo.deployment.environment
})
);
-};
+}
diff --git a/packages/opentelemetry/lib/config/tracing.js b/packages/opentelemetry/lib/config/tracing.js
index e12fd5cbe..c43992c84 100644
--- a/packages/opentelemetry/lib/config/tracing.js
+++ b/packages/opentelemetry/lib/config/tracing.js
@@ -1,8 +1,9 @@
-const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-proto');
-const { NoopSpanProcessor, TraceIdRatioBasedSampler } = require('@opentelemetry/sdk-node').tracing;
+import logger from '@dotcom-reliability-kit/logger';
+import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
+import { tracing } from '@opentelemetry/sdk-node';
+import { TRACING_USER_AGENT } from './user-agents.js';
-const { default: logger } = require('@dotcom-reliability-kit/logger');
-const { TRACING_USER_AGENT } = require('./user-agents.js');
+const { NoopSpanProcessor, TraceIdRatioBasedSampler } = tracing;
/**
* @import { NodeSDKConfiguration } from '@opentelemetry/sdk-node'
@@ -17,7 +18,7 @@ const DEFAULT_SAMPLE_PERCENTAGE = 5;
* @param {TracingOptions} options
* @returns {Partial}
*/
-exports.createTracingConfig = function createTracingConfig(options) {
+export function createTracingConfig(options) {
/** @type {Partial} */
const config = {};
@@ -61,4 +62,4 @@ exports.createTracingConfig = function createTracingConfig(options) {
}
return config;
-};
+}
diff --git a/packages/opentelemetry/lib/config/user-agents.js b/packages/opentelemetry/lib/config/user-agents.js
index d335f2cf6..5716fc6f6 100644
--- a/packages/opentelemetry/lib/config/user-agents.js
+++ b/packages/opentelemetry/lib/config/user-agents.js
@@ -1,9 +1,13 @@
-const appInfo = require('@dotcom-reliability-kit/app-info');
-const packageJson = require('../../package.json');
-const metricExporterPackageJson = require('@opentelemetry/exporter-metrics-otlp-proto/package.json');
-const traceExporterPackageJson = require('@opentelemetry/exporter-trace-otlp-proto/package.json');
+import appInfo from '@dotcom-reliability-kit/app-info';
+import metricExporterPackageJson from '@opentelemetry/exporter-metrics-otlp-proto/package.json' with {
+ type: 'json'
+};
+import traceExporterPackageJson from '@opentelemetry/exporter-trace-otlp-proto/package.json' with {
+ type: 'json'
+};
+import packageJson from '../../package.json' with { type: 'json' };
const BASE_USER_AGENT = `FTSystem/${appInfo.systemCode} (${packageJson.name}/${packageJson.version})`;
-exports.METRICS_USER_AGENT = `${BASE_USER_AGENT} (${metricExporterPackageJson.name}/${metricExporterPackageJson.version})`;
-exports.TRACING_USER_AGENT = `${BASE_USER_AGENT} (${traceExporterPackageJson.name}/${traceExporterPackageJson.version})`;
+export const METRICS_USER_AGENT = `${BASE_USER_AGENT} (${metricExporterPackageJson.name}/${metricExporterPackageJson.version})`;
+export const TRACING_USER_AGENT = `${BASE_USER_AGENT} (${traceExporterPackageJson.name}/${traceExporterPackageJson.version})`;
diff --git a/packages/opentelemetry/lib/config/views.js b/packages/opentelemetry/lib/config/views.js
index b4aa37a6f..faee03634 100644
--- a/packages/opentelemetry/lib/config/views.js
+++ b/packages/opentelemetry/lib/config/views.js
@@ -1,5 +1,7 @@
-const { AggregationType, InstrumentType } = require('@opentelemetry/sdk-node').metrics;
-const { default: logger } = require('@dotcom-reliability-kit/logger');
+import logger from '@dotcom-reliability-kit/logger';
+import { metrics } from '@opentelemetry/sdk-node';
+
+const { AggregationType, InstrumentType } = metrics;
/**
* @import { NodeSDKConfiguration } from '@opentelemetry/sdk-node'
@@ -13,10 +15,7 @@ const { default: logger } = require('@dotcom-reliability-kit/logger');
* @param {ViewOptions} options
* @returns {Partial}
*/
-exports.createViewConfig = function createViewConfig({
- httpClientDurationBuckets,
- httpServerDurationBuckets
-}) {
+export function createViewConfig({ httpClientDurationBuckets, httpServerDurationBuckets }) {
const views = [
...buildHistogramView({
instrumentName: 'http.client.duration',
@@ -30,7 +29,7 @@ exports.createViewConfig = function createViewConfig({
})
];
return views.length ? { views } : {};
-};
+}
/**
* @param {object} options
diff --git a/packages/opentelemetry/lib/index.js b/packages/opentelemetry/lib/index.js
index 40ff7bccc..6eb1ac1d9 100644
--- a/packages/opentelemetry/lib/index.js
+++ b/packages/opentelemetry/lib/index.js
@@ -1,11 +1,11 @@
-const { createInstrumentationConfig } = require('./config/instrumentations.js');
-const { createMetricsConfig } = require('./config/metrics.js');
-const { createResourceConfig } = require('./config/resource.js');
-const { createTracingConfig } = require('./config/tracing.js');
-const { createViewConfig } = require('./config/views.js');
-const { HostMetrics } = require('@opentelemetry/host-metrics');
-const opentelemetry = require('@opentelemetry/sdk-node');
-const { default: logger } = require('@dotcom-reliability-kit/logger');
+import logger from '@dotcom-reliability-kit/logger';
+import { HostMetrics } from '@opentelemetry/host-metrics';
+import opentelemetry from '@opentelemetry/sdk-node';
+import { createInstrumentationConfig } from './config/instrumentations.js';
+import { createMetricsConfig } from './config/metrics.js';
+import { createResourceConfig } from './config/resource.js';
+import { createTracingConfig } from './config/tracing.js';
+import { createViewConfig } from './config/views.js';
/**
* @import { Instances, Options } from '@dotcom-reliability-kit/opentelemetry'
@@ -25,7 +25,7 @@ let instances;
* @param {Options} [options]
* @returns {Instances}
*/
-function setupOpenTelemetry({
+export function setup({
authorizationHeader,
logInternals,
metrics: metricsOptions,
@@ -92,7 +92,12 @@ function setupOpenTelemetry({
// This is a known issue, the workaround is to import 'https' to ensure
// that the instrumented version is used by node-fetch. See:
// https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2440
- require('node:https');
+ import('node:https').catch(
+ // We need a catch here to ensure we don't exit the process if this fails
+ // for some reason, however we don't care about it in the test coverage
+ /* node:coverage ignore next */
+ () => {}
+ );
// Set up host metrics if we have a metrics endpoint
if (metricsOptions?.endpoint) {
@@ -114,7 +119,7 @@ function setupOpenTelemetry({
* @param {opentelemetry.api.MeterOptions} [options]
* @returns {opentelemetry.api.Meter}
*/
-function getMeter(name, version, options) {
+export function getMeter(name, version, options) {
if (!instances) {
throw Object.assign(
new Error(
@@ -128,5 +133,11 @@ function getMeter(name, version, options) {
return opentelemetry.api.metrics.getMeter(name, version, options);
}
-exports.setup = setupOpenTelemetry;
-exports.getMeter = getMeter;
+/**
+ * Helper method for us to clear instances during testing.
+ *
+ * @private
+ */
+export function clearInstances() {
+ instances = undefined;
+}
diff --git a/packages/opentelemetry/lib/setup-from-env.js b/packages/opentelemetry/lib/setup-from-env.js
new file mode 100644
index 000000000..b2e77f95c
--- /dev/null
+++ b/packages/opentelemetry/lib/setup-from-env.js
@@ -0,0 +1,59 @@
+import { setup } from './index.js';
+
+/**
+ * @import { MetricsOptions, TracingOptions, ViewOptions } from '@dotcom-reliability-kit/opentelemetry'
+ */
+
+/**
+ * @param {NodeJS.ProcessEnv} env
+ */
+export function setupFromEnv(env) {
+ /** @type {TracingOptions | undefined} */
+ let tracing;
+ if (env.OPENTELEMETRY_TRACING_ENDPOINT) {
+ tracing = {
+ authorizationHeader: env.OPENTELEMETRY_AUTHORIZATION_HEADER,
+ endpoint: env.OPENTELEMETRY_TRACING_ENDPOINT,
+ samplePercentage: env.OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE
+ ? Number(env.OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE)
+ : undefined
+ };
+ }
+
+ /** @type {MetricsOptions | undefined} */
+ let metrics;
+ if (env.OPENTELEMETRY_METRICS_ENDPOINT) {
+ metrics = {
+ apiGatewayKey: env.OPENTELEMETRY_API_GATEWAY_KEY,
+ endpoint: env.OPENTELEMETRY_METRICS_ENDPOINT
+ };
+ }
+
+ /**
+ * @param {string} input
+ * @returns {number[]}
+ */
+ function parseListOfNumbers(input) {
+ return input.split(',').map((item) => Number(item.trim()));
+ }
+
+ /** @type {ViewOptions} */
+ const views = {};
+ if (env.OPENTELEMETRY_VIEWS_HTTP_SERVER_DURATION_BUCKETS) {
+ views.httpServerDurationBuckets = parseListOfNumbers(
+ env.OPENTELEMETRY_VIEWS_HTTP_SERVER_DURATION_BUCKETS
+ );
+ }
+ if (env.OPENTELEMETRY_VIEWS_HTTP_CLIENT_DURATION_BUCKETS) {
+ views.httpClientDurationBuckets = parseListOfNumbers(
+ env.OPENTELEMETRY_VIEWS_HTTP_CLIENT_DURATION_BUCKETS
+ );
+ }
+
+ setup({
+ logInternals: Boolean(env.OPENTELEMETRY_LOG_INTERNALS),
+ metrics,
+ tracing,
+ views
+ });
+}
diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json
index 864e6cc23..7bd83a1f1 100644
--- a/packages/opentelemetry/package.json
+++ b/packages/opentelemetry/package.json
@@ -1,6 +1,7 @@
{
"name": "@dotcom-reliability-kit/opentelemetry",
"version": "3.2.5",
+ "type": "module",
"description": "An OpenTelemetry client that's preconfigured for drop-in use in FT apps.",
"repository": {
"type": "git",
diff --git a/packages/opentelemetry/setup.js b/packages/opentelemetry/setup.js
index 89375a5e9..355e49195 100644
--- a/packages/opentelemetry/setup.js
+++ b/packages/opentelemetry/setup.js
@@ -1,54 +1,3 @@
-const opentelemetry = require('./lib/index.js');
+import { setupFromEnv } from './lib/setup-from-env.js';
-/**
- * @import { MetricsOptions, TracingOptions, ViewOptions } from '@dotcom-reliability-kit/opentelemetry'
- */
-
-/** @type {TracingOptions | undefined} */
-let tracing;
-if (process.env.OPENTELEMETRY_TRACING_ENDPOINT) {
- tracing = {
- authorizationHeader: process.env.OPENTELEMETRY_AUTHORIZATION_HEADER,
- endpoint: process.env.OPENTELEMETRY_TRACING_ENDPOINT,
- samplePercentage: process.env.OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE
- ? Number(process.env.OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE)
- : undefined
- };
-}
-
-/** @type {MetricsOptions | undefined} */
-let metrics;
-if (process.env.OPENTELEMETRY_METRICS_ENDPOINT) {
- metrics = {
- apiGatewayKey: process.env.OPENTELEMETRY_API_GATEWAY_KEY,
- endpoint: process.env.OPENTELEMETRY_METRICS_ENDPOINT
- };
-}
-
-/**
- * @param {string} input
- * @returns {number[]}
- */
-function parseListOfNumbers(input) {
- return input.split(',').map((item) => Number(item.trim()));
-}
-
-/** @type {ViewOptions} */
-const views = {};
-if (process.env.OPENTELEMETRY_VIEWS_HTTP_SERVER_DURATION_BUCKETS) {
- views.httpServerDurationBuckets = parseListOfNumbers(
- process.env.OPENTELEMETRY_VIEWS_HTTP_SERVER_DURATION_BUCKETS
- );
-}
-if (process.env.OPENTELEMETRY_VIEWS_HTTP_CLIENT_DURATION_BUCKETS) {
- views.httpClientDurationBuckets = parseListOfNumbers(
- process.env.OPENTELEMETRY_VIEWS_HTTP_CLIENT_DURATION_BUCKETS
- );
-}
-
-opentelemetry.setup({
- logInternals: Boolean(process.env.OPENTELEMETRY_LOG_INTERNALS),
- metrics,
- tracing,
- views
-});
+setupFromEnv(process.env);
diff --git a/packages/opentelemetry/test/end-to-end/fixtures/app.js b/packages/opentelemetry/test/end-to-end/fixtures/app.js
index e0ae0dabc..db6a7e467 100644
--- a/packages/opentelemetry/test/end-to-end/fixtures/app.js
+++ b/packages/opentelemetry/test/end-to-end/fixtures/app.js
@@ -1,8 +1,8 @@
-const express = require('express');
-const { default: logger } = require('@dotcom-reliability-kit/logger');
+import logger from '@dotcom-reliability-kit/logger';
+// We set up OpenTelemetry via `--import` but this allows us to grab the same instances
+import { setup } from '@dotcom-reliability-kit/opentelemetry';
+import express from 'express';
-// We set up OpenTelemetry via `--require` but this allows us to grab the same instances
-const { setup } = require('@dotcom-reliability-kit/opentelemetry');
const { sdk } = setup();
const app = express();
diff --git a/packages/opentelemetry/test/end-to-end/fixtures/collector.js b/packages/opentelemetry/test/end-to-end/fixtures/collector.js
index b41325ca5..43d46f91d 100644
--- a/packages/opentelemetry/test/end-to-end/fixtures/collector.js
+++ b/packages/opentelemetry/test/end-to-end/fixtures/collector.js
@@ -1,5 +1,5 @@
-const express = require('express');
-const { default: logger } = require('@dotcom-reliability-kit/logger');
+import logger from '@dotcom-reliability-kit/logger';
+import express from 'express';
const app = express();
diff --git a/packages/opentelemetry/test/end-to-end/index.spec.js b/packages/opentelemetry/test/end-to-end/index.spec.js
index 92a5ae2eb..a7c5a1545 100644
--- a/packages/opentelemetry/test/end-to-end/index.spec.js
+++ b/packages/opentelemetry/test/end-to-end/index.spec.js
@@ -1,7 +1,7 @@
-const { after, before, describe, it } = require('node:test');
-const assert = require('node:assert/strict');
-const { fork } = require('node:child_process');
-const { setTimeout } = require('node:timers/promises');
+import assert from 'node:assert/strict';
+import { fork } from 'node:child_process';
+import { after, before, describe, it } from 'node:test';
+import { setTimeout } from 'node:timers/promises';
function waitForBaseUrl(childProcess) {
return new Promise((resolve) => {
@@ -35,7 +35,7 @@ describe('@dotcom-reliability-kit/opentelemetry end-to-end', () => {
before(async () => {
// Set up a mock collector
- collector = fork(`${__dirname}/fixtures/collector.js`, {
+ collector = fork(`${import.meta.dirname}/fixtures/collector.js`, {
env: {
...process.env,
NODE_ENV: 'production',
@@ -52,7 +52,7 @@ describe('@dotcom-reliability-kit/opentelemetry end-to-end', () => {
collectorBaseUrl = await waitForBaseUrl(collector);
// Set up a Node.js app that sends Opentelemetry metrics and traces
- exporter = fork(`${__dirname}/fixtures/app.js`, {
+ exporter = fork(`${import.meta.dirname}/fixtures/app.js`, {
env: {
...process.env,
NODE_ENV: 'production',
@@ -61,7 +61,7 @@ describe('@dotcom-reliability-kit/opentelemetry end-to-end', () => {
OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE: '100',
SYSTEM_CODE: 'mock-system'
},
- execArgv: ['--require', '@dotcom-reliability-kit/opentelemetry/setup'],
+ execArgv: ['--import', '@dotcom-reliability-kit/opentelemetry/setup'],
stdio: 'pipe'
});
exporter.stdout.on('data', (chunk) => {
diff --git a/packages/opentelemetry/test/unit/lib/config/instrumentations.spec.js b/packages/opentelemetry/test/unit/lib/config/instrumentations.spec.js
index ac0dce5b2..e37b9248f 100644
--- a/packages/opentelemetry/test/unit/lib/config/instrumentations.spec.js
+++ b/packages/opentelemetry/test/unit/lib/config/instrumentations.spec.js
@@ -1,5 +1,5 @@
-const { before, beforeEach, describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
+import assert from 'node:assert/strict';
+import { before, beforeEach, describe, it, mock } from 'node:test';
const getNodeAutoInstrumentations = mock.fn(() => 'mock-auto-instrumentations');
mock.module('@opentelemetry/auto-instrumentations-node', {
@@ -12,7 +12,7 @@ mock.module('@dotcom-reliability-kit/log-error', { namedExports: { logRecoverabl
const UserInputError = mock.fn(class UserInputError {});
mock.module('@dotcom-reliability-kit/errors', { namedExports: { UserInputError } });
-const { createInstrumentationConfig } = require('../../../../lib/config/instrumentations.js');
+const { createInstrumentationConfig } = await import('../../../../lib/config/instrumentations.js');
describe('@dotcom-reliability-kit/opentelemetry/lib/config/instrumentation', () => {
it('exports a function', () => {
diff --git a/packages/opentelemetry/test/unit/lib/config/metrics.spec.js b/packages/opentelemetry/test/unit/lib/config/metrics.spec.js
index b6877cc99..f4bbddd71 100644
--- a/packages/opentelemetry/test/unit/lib/config/metrics.spec.js
+++ b/packages/opentelemetry/test/unit/lib/config/metrics.spec.js
@@ -1,12 +1,8 @@
-const { before, describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
+import assert from 'node:assert/strict';
+import { before, describe, it, mock } from 'node:test';
const logger = { info: mock.fn() };
-mock.module('@dotcom-reliability-kit/logger', {
- // NOTE: this is temporary while we're importing ESM into CommonJS.
- // Should be switched back when we migrate opentelemetry to ESM.
- namedExports: { default: logger }
-});
+mock.module('@dotcom-reliability-kit/logger', { defaultExport: logger });
mock.module('../../../../lib/config/user-agents.js', {
namedExports: { METRICS_USER_AGENT: 'mock-metrics-user-agent' }
@@ -24,7 +20,7 @@ mock.module('@opentelemetry/otlp-exporter-base', {
namedExports: { CompressionAlgorithm: { GZIP: 'gzip' } }
});
-const { createMetricsConfig } = require('../../../../lib/config/metrics');
+const { createMetricsConfig } = await import('../../../../lib/config/metrics.js');
describe('@dotcom-reliability-kit/opentelemetry/lib/config/metrics', () => {
it('exports a function', () => {
diff --git a/packages/opentelemetry/test/unit/lib/config/resource.spec.js b/packages/opentelemetry/test/unit/lib/config/resource.spec.js
index be47a7544..bcd8238c2 100644
--- a/packages/opentelemetry/test/unit/lib/config/resource.spec.js
+++ b/packages/opentelemetry/test/unit/lib/config/resource.spec.js
@@ -1,5 +1,5 @@
-const { beforeEach, describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
+import assert from 'node:assert/strict';
+import { beforeEach, describe, it, mock } from 'node:test';
const appInfo = {
semanticConventions: {
@@ -19,12 +19,12 @@ const appInfo = {
}
}
};
-mock.module('@dotcom-reliability-kit/app-info', { defaultExport: appInfo });
+mock.module('@dotcom-reliability-kit/app-info', { namedExports: appInfo });
const defaultResource = mock.fn(() => ({ merge: mock.fn(() => 'mock-merged-resource') }));
const resourceFromAttributes = mock.fn(() => 'mock-resource');
mock.module('@opentelemetry/sdk-node', {
- defaultExport: { resources: { defaultResource, resourceFromAttributes } }
+ namedExports: { resources: { defaultResource, resourceFromAttributes } }
});
mock.module('@opentelemetry/semantic-conventions', {
@@ -34,7 +34,7 @@ mock.module('@opentelemetry/semantic-conventions', {
}
});
-const { createResourceConfig } = require('../../../../lib/config/resource.js');
+const { createResourceConfig } = await import('../../../../lib/config/resource.js');
describe('@dotcom-reliability-kit/opentelemetry/lib/config/resource', () => {
it('exports a function', () => {
diff --git a/packages/opentelemetry/test/unit/lib/config/tracing.spec.js b/packages/opentelemetry/test/unit/lib/config/tracing.spec.js
index ba9cac1b0..fb847e4f6 100644
--- a/packages/opentelemetry/test/unit/lib/config/tracing.spec.js
+++ b/packages/opentelemetry/test/unit/lib/config/tracing.spec.js
@@ -1,12 +1,8 @@
-const { before, describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
+import assert from 'node:assert/strict';
+import { before, describe, it, mock } from 'node:test';
const logger = { info: mock.fn() };
-mock.module('@dotcom-reliability-kit/logger', {
- // NOTE: this is temporary while we're importing ESM into CommonJS.
- // Should be switched back when we migrate opentelemetry to ESM.
- namedExports: { default: logger }
-});
+mock.module('@dotcom-reliability-kit/logger', { defaultExport: logger });
mock.module('../../../../lib/config/user-agents.js', {
namedExports: { TRACING_USER_AGENT: 'mock-tracing-user-agent' }
@@ -21,7 +17,7 @@ mock.module('@opentelemetry/sdk-node', {
namedExports: { tracing: { NoopSpanProcessor, TraceIdRatioBasedSampler } }
});
-const { createTracingConfig } = require('../../../../lib/config/tracing.js');
+const { createTracingConfig } = await import('../../../../lib/config/tracing.js');
describe('@dotcom-reliability-kit/opentelemetry/lib/config/tracing', () => {
it('exports a function', () => {
diff --git a/packages/opentelemetry/test/unit/lib/config/user-agents.spec.js b/packages/opentelemetry/test/unit/lib/config/user-agents.spec.js
index 48df2a200..fb4bf1acb 100644
--- a/packages/opentelemetry/test/unit/lib/config/user-agents.spec.js
+++ b/packages/opentelemetry/test/unit/lib/config/user-agents.spec.js
@@ -1,5 +1,5 @@
-const { describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
+import assert from 'node:assert/strict';
+import { describe, it, mock } from 'node:test';
const appInfo = { systemCode: 'mock-system-code' };
mock.module('@dotcom-reliability-kit/app-info', { defaultExport: appInfo });
@@ -24,7 +24,9 @@ mock.module('@opentelemetry/exporter-trace-otlp-proto/package.json', {
}
});
-const { METRICS_USER_AGENT, TRACING_USER_AGENT } = require('../../../../lib/config/user-agents.js');
+const { METRICS_USER_AGENT, TRACING_USER_AGENT } = await import(
+ '../../../../lib/config/user-agents.js'
+);
describe('@dotcom-reliability-kit/opentelemetry/lib/config/resource', () => {
describe('.METRICS_USER_AGENT', () => {
diff --git a/packages/opentelemetry/test/unit/lib/config/views.spec.js b/packages/opentelemetry/test/unit/lib/config/views.spec.js
index 99aa0ad0a..ea501a962 100644
--- a/packages/opentelemetry/test/unit/lib/config/views.spec.js
+++ b/packages/opentelemetry/test/unit/lib/config/views.spec.js
@@ -1,20 +1,16 @@
-const { before, describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
+import assert from 'node:assert/strict';
+import { before, describe, it, mock } from 'node:test';
const logger = { warn: mock.fn() };
-mock.module('@dotcom-reliability-kit/logger', {
- // NOTE: this is temporary while we're importing ESM into CommonJS.
- // Should be switched back when we migrate opentelemetry to ESM.
- namedExports: { default: logger }
-});
+mock.module('@dotcom-reliability-kit/logger', { defaultExport: logger });
const metrics = {
AggregationType: { EXPLICIT_BUCKET_HISTOGRAM: 'mock-explicit-bucket' },
InstrumentType: { HISTOGRAM: 'mock-histogram' }
};
-mock.module('@opentelemetry/sdk-node', { defaultExport: { metrics } });
+mock.module('@opentelemetry/sdk-node', { namedExports: { metrics } });
-const { createViewConfig } = require('../../../../lib/config/views');
+const { createViewConfig } = await import('../../../../lib/config/views.js');
describe('@dotcom-reliability-kit/opentelemetry/lib/config/views', () => {
it('exports a function', () => {
diff --git a/packages/opentelemetry/test/unit/lib/index.spec.js b/packages/opentelemetry/test/unit/lib/index.spec.js
index 636f48954..83925dfc7 100644
--- a/packages/opentelemetry/test/unit/lib/index.spec.js
+++ b/packages/opentelemetry/test/unit/lib/index.spec.js
@@ -1,101 +1,60 @@
-const { before, beforeEach, describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
-
-mock.module('@dotcom-reliability-kit/logger', {
- // NOTE: this is temporary while we're importing ESM into CommonJS.
- // Should be switched back when we migrate opentelemetry to ESM.
- namedExports: { default: { createChildLogger: mock.fn(), warn: mock.fn() } }
-});
-
-mock.module('@opentelemetry/sdk-node', {
- defaultExport: {
- api: {
- diag: { disable: mock.fn(), setLogger: mock.fn() },
- DiagLogLevel: {},
- metrics: {
- getMeter: mock.fn(() => 'mock-meter'),
- getMeterProvider: mock.fn(() => 'mock-meter-provider')
- }
- },
- NodeSDK: mock.fn(
- class NodeSDK {
- start = mock.fn();
- }
- )
+import assert from 'node:assert/strict';
+import { before, beforeEach, describe, it, mock } from 'node:test';
+
+const mockChildLogger = {
+ debug: mock.fn(),
+ error: mock.fn(),
+ info: mock.fn(),
+ verbose: mock.fn(),
+ warn: mock.fn()
+};
+const logger = { createChildLogger: mock.fn(() => mockChildLogger), warn: mock.fn() };
+mock.module('@dotcom-reliability-kit/logger', { defaultExport: logger });
+
+const api = {
+ diag: { disable: mock.fn(), setLogger: mock.fn() },
+ DiagLogLevel: {
+ INFO: 'mock info log level'
+ },
+ metrics: {
+ getMeter: mock.fn(() => 'mock-meter'),
+ getMeterProvider: mock.fn(() => 'mock-meter-provider')
}
-});
+};
+const NodeSDK = mock.fn(
+ class NodeSDK {
+ start = mock.fn();
+ }
+);
+mock.module('@opentelemetry/sdk-node', { defaultExport: { api, NodeSDK } });
-mock.module('@opentelemetry/host-metrics', {
- namedExports: {
- HostMetrics: mock.fn(
- class HostMetrics {
- start = mock.fn();
- }
- )
+const HostMetrics = mock.fn(
+ class HostMetrics {
+ start = mock.fn();
}
-});
+);
+mock.module('@opentelemetry/host-metrics', { namedExports: { HostMetrics } });
+const createInstrumentationConfig = mock.fn(() => 'mock-instrumentations');
mock.module('../../../lib/config/instrumentations.js', {
- namedExports: { createInstrumentationConfig: mock.fn(() => 'mock-instrumentations') }
-});
-mock.module('../../../lib/config/metrics.js', {
- namedExports: { createMetricsConfig: mock.fn(() => ({ metrics: 'mock-metrics' })) }
-});
-mock.module('../../../lib/config/resource.js', {
- namedExports: { createResourceConfig: mock.fn(() => 'mock-resource') }
-});
-mock.module('../../../lib/config/tracing.js', {
- namedExports: { createTracingConfig: mock.fn(() => ({ tracing: 'mock-tracing' })) }
-});
-mock.module('../../../lib/config/views.js', {
- namedExports: { createViewConfig: mock.fn(() => ({ views: 'mock-views' })) }
+ namedExports: { createInstrumentationConfig }
});
-describe('@dotcom-reliability-kit/opentelemetry', () => {
- let api;
- let createInstrumentationConfig;
- let createMetricsConfig;
- let createResourceConfig;
- let createTracingConfig;
- let createViewConfig;
- let HostMetrics;
- let logger;
- let mockChildLogger;
- let NodeSDK;
- let opentelemetry;
-
- // Helper function to reload all modules. We need this because the setup
- // method stores a global singleton so it's impossible to call it multiple
- // times with different configuration values normally. We need to do this
- // in the tests though
- function reloadAllModules() {
- createInstrumentationConfig =
- require('../../../lib/config/instrumentations.js').createInstrumentationConfig;
- createMetricsConfig = require('../../../lib/config/metrics.js').createMetricsConfig;
- createResourceConfig = require('../../../lib/config/resource.js').createResourceConfig;
- createTracingConfig = require('../../../lib/config/tracing.js').createTracingConfig;
- createViewConfig = require('../../../lib/config/views.js').createViewConfig;
- api = require('@opentelemetry/sdk-node').api;
- HostMetrics = require('@opentelemetry/host-metrics').HostMetrics;
- NodeSDK = require('@opentelemetry/sdk-node').NodeSDK;
- logger = require('@dotcom-reliability-kit/logger').default;
-
- mockChildLogger = {
- debug: mock.fn(),
- error: mock.fn(),
- info: mock.fn(),
- verbose: mock.fn(),
- warn: mock.fn()
- };
- logger.createChildLogger.mock.mockImplementation(() => mockChildLogger);
- api.DiagLogLevel.INFO = 'mock info log level';
-
- delete require.cache[require.resolve('../../../lib/index.js')];
- opentelemetry = require('../../../lib/index.js');
- }
+const createMetricsConfig = mock.fn(() => ({ metrics: 'mock-metrics' }));
+mock.module('../../../lib/config/metrics.js', { namedExports: { createMetricsConfig } });
- before(reloadAllModules);
+const createResourceConfig = mock.fn(() => 'mock-resource');
+mock.module('../../../lib/config/resource.js', { namedExports: { createResourceConfig } });
+const createTracingConfig = mock.fn(() => ({ tracing: 'mock-tracing' }));
+mock.module('../../../lib/config/tracing.js', { namedExports: { createTracingConfig } });
+
+const createViewConfig = mock.fn(() => ({ views: 'mock-views' }));
+mock.module('../../../lib/config/views.js', { namedExports: { createViewConfig } });
+
+const opentelemetry = await import('../../../lib/index.js');
+
+describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('.setup(options)', () => {
let instances;
@@ -195,7 +154,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
api.diag.disable.mock.resetCalls();
logger.createChildLogger.mock.resetCalls();
NodeSDK.mock.resetCalls();
- reloadAllModules();
+ opentelemetry.clearInstances();
instances = opentelemetry.setup({
logInternals: true,
tracing: {
@@ -293,7 +252,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('when no metrics endpoint is set', () => {
beforeEach(() => {
HostMetrics.mock.resetCalls();
- reloadAllModules();
+ opentelemetry.clearInstances();
instances = opentelemetry.setup({
tracing: {
endpoint: 'mock-tracing-endpoint',
@@ -314,7 +273,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('when no options are set', () => {
beforeEach(() => {
NodeSDK.mock.resetCalls();
- reloadAllModules();
+ opentelemetry.clearInstances();
opentelemetry.setup();
});
@@ -335,7 +294,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('when an authorization header is passed into the root options (deprecated)', () => {
beforeEach(() => {
createTracingConfig.mock.resetCalls();
- reloadAllModules();
+ opentelemetry.clearInstances();
opentelemetry.setup({
authorizationHeader: 'mock-authorization-header-root',
tracing: {
@@ -358,7 +317,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('when an authorization header is passed into the tracing options', () => {
beforeEach(() => {
createTracingConfig.mock.resetCalls();
- reloadAllModules();
+ opentelemetry.clearInstances();
opentelemetry.setup({
tracing: {
authorizationHeader: 'mock-authorization-header-tracing',
@@ -381,7 +340,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('when an authorization header is passed into both the root options (deprecated) and tracing options', () => {
beforeEach(() => {
createTracingConfig.mock.resetCalls();
- reloadAllModules();
+ opentelemetry.clearInstances();
opentelemetry.setup({
authorizationHeader: 'mock-authorization-header-root',
tracing: {
@@ -405,7 +364,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('when OTEL_ environment variables are defined', () => {
beforeEach(() => {
process.env.OTEL_MOCK = 'mock';
- reloadAllModules();
+ opentelemetry.clearInstances();
opentelemetry.setup();
});
@@ -426,7 +385,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
beforeEach(() => {
NodeSDK.mock.resetCalls();
- reloadAllModules();
+ opentelemetry.clearInstances();
returnValue1 = opentelemetry.setup({
tracing: {
endpoint: 'mock-tracing-endpoint',
@@ -463,7 +422,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
let meter;
beforeEach(() => {
- reloadAllModules();
+ opentelemetry.clearInstances();
opentelemetry.setup();
meter = opentelemetry.getMeter('mock-name', 'mock-version', 'mock-options');
});
@@ -480,7 +439,7 @@ describe('@dotcom-reliability-kit/opentelemetry', () => {
describe('when OpenTelemetry has not been set up via Reliability Kit', () => {
beforeEach(() => {
- reloadAllModules();
+ opentelemetry.clearInstances();
});
it('throws an error', () => {
diff --git a/packages/opentelemetry/test/unit/lib/setup-from-env.spec.js b/packages/opentelemetry/test/unit/lib/setup-from-env.spec.js
new file mode 100644
index 000000000..8b30c669e
--- /dev/null
+++ b/packages/opentelemetry/test/unit/lib/setup-from-env.spec.js
@@ -0,0 +1,177 @@
+import assert from 'node:assert/strict';
+import { beforeEach, describe, it, mock } from 'node:test';
+
+const opentelemetry = { setup: mock.fn() };
+mock.module('../../../lib/index.js', { namedExports: opentelemetry });
+
+const { setupFromEnv } = await import('../../../lib/setup-from-env.js');
+
+describe('@dotcom-reliability-kit/opentelemetry/lib/setup-from-env', () => {
+ beforeEach(() => {
+ opentelemetry.setup.mock.resetCalls();
+ });
+
+ describe('.setupFromEnv(env)', () => {
+ it('calls opentelemetry.setup with the correct parameters', () => {
+ setupFromEnv({
+ OPENTELEMETRY_TRACING_ENDPOINT: 'MOCK_TRACING_ENDPOINT',
+ OPENTELEMETRY_AUTHORIZATION_HEADER: 'MOCK_AUTH_HEADER',
+ OPENTELEMETRY_METRICS_ENDPOINT: 'MOCK_METRICS_ENDPOINT',
+ OPENTELEMETRY_API_GATEWAY_KEY: 'MOCK_API_GATEWAY_KEY'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ logInternals: false,
+ tracing: {
+ authorizationHeader: 'MOCK_AUTH_HEADER',
+ endpoint: 'MOCK_TRACING_ENDPOINT'
+ },
+ metrics: {
+ apiGatewayKey: 'MOCK_API_GATEWAY_KEY',
+ endpoint: 'MOCK_METRICS_ENDPOINT'
+ },
+ views: {}
+ }
+ ]);
+ });
+
+ describe('when no traces endpoint is specified', () => {
+ it('should not include tracing configuration', () => {
+ setupFromEnv({
+ OPENTELEMETRY_METRICS_ENDPOINT: 'MOCK_METRICS_ENDPOINT',
+ OPENTELEMETRY_API_GATEWAY_KEY: 'MOCK_API_GATEWAY_KEY'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ logInternals: false,
+ metrics: {
+ apiGatewayKey: 'MOCK_API_GATEWAY_KEY',
+ endpoint: 'MOCK_METRICS_ENDPOINT'
+ },
+ views: {}
+ }
+ ]);
+ });
+ });
+
+ describe('when no metrics endpoint is specified', () => {
+ it('should not include metrics configuration', () => {
+ setupFromEnv({
+ OPENTELEMETRY_TRACING_ENDPOINT: 'MOCK_TRACING_ENDPOINT',
+ OPENTELEMETRY_AUTHORIZATION_HEADER: 'MOCK_AUTH_HEADER'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ logInternals: false,
+ tracing: {
+ authorizationHeader: 'MOCK_AUTH_HEADER',
+ endpoint: 'MOCK_TRACING_ENDPOINT'
+ },
+ views: {}
+ }
+ ]);
+ });
+ });
+
+ describe('when an HTTP server duration bucket is specified', () => {
+ it('includes views configurations', () => {
+ setupFromEnv({
+ OPENTELEMETRY_VIEWS_HTTP_SERVER_DURATION_BUCKETS: '1,2,3, 4 ,five'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ views: {
+ httpServerDurationBuckets: [1, 2, 3, 4, NaN]
+ }
+ }
+ ]);
+ });
+ });
+
+ describe('when an HTTP client duration bucket is specified', () => {
+ it('includes views configurations', () => {
+ setupFromEnv({
+ OPENTELEMETRY_VIEWS_HTTP_CLIENT_DURATION_BUCKETS: '1,2,3, 4 ,five'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ views: {
+ httpClientDurationBuckets: [1, 2, 3, 4, NaN]
+ }
+ }
+ ]);
+ });
+ });
+
+ describe('when a sample rate is specified', () => {
+ it('calls OpenTelemetry with the given sample percentage as a number', () => {
+ setupFromEnv({
+ OPENTELEMETRY_TRACING_ENDPOINT: 'MOCK_TRACING_ENDPOINT',
+ OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE: '50',
+ OPENTELEMETRY_AUTHORIZATION_HEADER: 'MOCK_AUTH_HEADER'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ logInternals: false,
+ tracing: {
+ authorizationHeader: 'MOCK_AUTH_HEADER',
+ endpoint: 'MOCK_TRACING_ENDPOINT',
+ samplePercentage: 50
+ },
+ views: {}
+ }
+ ]);
+ });
+ });
+
+ describe('when a non-numeric sample rate is specified', () => {
+ it('calls OpenTelemetry with NaN as a percentage', () => {
+ setupFromEnv({
+ OPENTELEMETRY_TRACING_ENDPOINT: 'MOCK_TRACING_ENDPOINT',
+ OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE: 'nope',
+ OPENTELEMETRY_AUTHORIZATION_HEADER: 'MOCK_AUTH_HEADER'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ logInternals: false,
+ tracing: {
+ authorizationHeader: 'MOCK_AUTH_HEADER',
+ endpoint: 'MOCK_TRACING_ENDPOINT',
+ samplePercentage: NaN
+ },
+ views: {}
+ }
+ ]);
+ });
+ });
+
+ describe('when internal logs are enabled', () => {
+ it('calls OpenTelemetry with the logInternal option set to true', () => {
+ setupFromEnv({
+ OPENTELEMETRY_LOG_INTERNALS: 'true'
+ });
+
+ assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
+ assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
+ {
+ logInternals: true
+ }
+ ]);
+ });
+ });
+ });
+});
diff --git a/packages/opentelemetry/test/unit/setup.spec.js b/packages/opentelemetry/test/unit/setup.spec.js
index e7283fb45..fa8953596 100644
--- a/packages/opentelemetry/test/unit/setup.spec.js
+++ b/packages/opentelemetry/test/unit/setup.spec.js
@@ -1,175 +1,17 @@
-const { beforeEach, describe, it, mock } = require('node:test');
-const assert = require('node:assert/strict');
+import assert from 'node:assert/strict';
+import { beforeEach, describe, it, mock } from 'node:test';
-describe('setup', () => {
- let opentelemetry;
-
- beforeEach((test) => {
- mock.restoreAll();
- opentelemetry = { setup: mock.fn() };
- test.mock.module('../../lib/index.js', { defaultExport: opentelemetry });
- });
-
- it('calls opentelemetry.setup with the correct parameters', () => {
- delete process.env.OPENTELEMETRY_LOG_INTERNALS;
- process.env.OPENTELEMETRY_TRACING_ENDPOINT = 'MOCK_TRACING_ENDPOINT';
- process.env.OPENTELEMETRY_AUTHORIZATION_HEADER = 'MOCK_AUTH_HEADER';
- process.env.OPENTELEMETRY_METRICS_ENDPOINT = 'MOCK_METRICS_ENDPOINT';
- process.env.OPENTELEMETRY_API_GATEWAY_KEY = 'MOCK_API_GATEWAY_KEY';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- logInternals: false,
- tracing: {
- authorizationHeader: 'MOCK_AUTH_HEADER',
- endpoint: 'MOCK_TRACING_ENDPOINT'
- },
- metrics: {
- apiGatewayKey: 'MOCK_API_GATEWAY_KEY',
- endpoint: 'MOCK_METRICS_ENDPOINT'
- },
- views: {}
- }
- ]);
- });
-
- describe('when no traces endpoint is specified', () => {
- it('should not include tracing configuration', () => {
- delete process.env.OPENTELEMETRY_TRACING_ENDPOINT;
- process.env.OPENTELEMETRY_METRICS_ENDPOINT = 'MOCK_METRICS_ENDPOINT';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- logInternals: false,
- metrics: {
- apiGatewayKey: 'MOCK_API_GATEWAY_KEY',
- endpoint: 'MOCK_METRICS_ENDPOINT'
- },
- views: {}
- }
- ]);
- });
- });
-
- describe('when no metrics endpoint is specified', () => {
- it('should not include metrics configuration', () => {
- delete process.env.OPENTELEMETRY_METRICS_ENDPOINT;
- process.env.OPENTELEMETRY_TRACING_ENDPOINT = 'MOCK_TRACING_ENDPOINT';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- logInternals: false,
- tracing: {
- authorizationHeader: 'MOCK_AUTH_HEADER',
- endpoint: 'MOCK_TRACING_ENDPOINT'
- },
- views: {}
- }
- ]);
- });
- });
+const setupFromEnv = mock.fn();
+mock.module('../../lib/setup-from-env.js', { namedExports: { setupFromEnv } });
- describe('when an HTTP server duration bucket is specified', () => {
- it('includes views configurations', () => {
- process.env.OPENTELEMETRY_VIEWS_HTTP_SERVER_DURATION_BUCKETS = '1,2,3, 4 ,five';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- views: {
- httpServerDurationBuckets: [1, 2, 3, 4, NaN]
- }
- }
- ]);
- delete process.env.OPENTELEMETRY_VIEWS_HTTP_SERVER_DURATION_BUCKETS;
- });
- });
-
- describe('when an HTTP client duration bucket is specified', () => {
- it('includes views configurations', () => {
- process.env.OPENTELEMETRY_VIEWS_HTTP_CLIENT_DURATION_BUCKETS = '1,2,3, 4 ,five';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- views: {
- httpClientDurationBuckets: [1, 2, 3, 4, NaN]
- }
- }
- ]);
- delete process.env.OPENTELEMETRY_VIEWS_HTTP_CLIENT_DURATION_BUCKETS;
- });
- });
-
- describe('when a sample rate is specified', () => {
- it('calls OpenTelemetry with the given sample percentage as a number', () => {
- delete process.env.OPENTELEMETRY_METRICS_ENDPOINT;
- process.env.OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE = '50';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- logInternals: false,
- tracing: {
- authorizationHeader: 'MOCK_AUTH_HEADER',
- endpoint: 'MOCK_TRACING_ENDPOINT',
- samplePercentage: 50
- },
- views: {}
- }
- ]);
- });
- });
-
- describe('when a non-numeric sample rate is specified', () => {
- it('calls OpenTelemetry with NaN as a percentage', () => {
- delete process.env.OPENTELEMETRY_METRICS_ENDPOINT;
- process.env.OPENTELEMETRY_TRACING_SAMPLE_PERCENTAGE = 'nope';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- logInternals: false,
- tracing: {
- authorizationHeader: 'MOCK_AUTH_HEADER',
- endpoint: 'MOCK_TRACING_ENDPOINT',
- samplePercentage: NaN
- },
- views: {}
- }
- ]);
- });
+describe('setup', () => {
+ beforeEach(async () => {
+ mock.property(process, 'env', { MOCK_ENV: 'true' });
+ await import('../../setup.js');
});
- describe('when internal logs are enabled', () => {
- it('calls OpenTelemetry with the logInternal option set to true', () => {
- process.env.OPENTELEMETRY_LOG_INTERNALS = 'true';
- delete require.cache[require.resolve('@dotcom-reliability-kit/opentelemetry/setup')];
- require('@dotcom-reliability-kit/opentelemetry/setup');
-
- assert.strictEqual(opentelemetry.setup.mock.callCount(), 1);
- assert.partialDeepStrictEqual(opentelemetry.setup.mock.calls[0].arguments, [
- {
- logInternals: true
- }
- ]);
- });
+ it('calls setupFromEnv with proces.env', () => {
+ assert.strictEqual(setupFromEnv.mock.callCount(), 1);
+ assert.deepStrictEqual(setupFromEnv.mock.calls[0].arguments, [{ MOCK_ENV: 'true' }]);
});
});