diff --git a/README.md b/README.md index e51a619..cddb44f 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ This can be disabled either by setting `OTEL_SERVICE_NAME` or by setting `DASH0_ Additional debug logs can be enabled by setting `DASH0_DEBUG=true`. +### DASH0_DISABLE + +Disables the Dash0 Node.js distribution entirely. + ### DASH0_ENABLE_FS_INSTRUMENTATION By default, the instrumentation plug-in `@opentelemetry/instrumentation-fs` is disabled. Set `DASH0_ENABLE_FS_INSTRUMENTATION=true` to enable spans for file system access. diff --git a/src/index.ts b/src/index.ts index 4ca8c09..878f98c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,7 +36,11 @@ function init() { } } -init(); +if (process.env.DASH0_DISABLE == null || process.env.DASH0_DISABLE.toLowerCase() !== 'true') { + init(); +} else { + logProhibitiveError(`The distribution has been disabled by setting DASH0_DISABLE=${process.env.DASH0_DISABLE}.`); +} function logProhibitiveError(message: string) { console.error(`[${prefix}] ${message} OpenTelemetry data will not be sent to Dash0.`); diff --git a/test/collector/CollectorChildProcessWrapper.ts b/test/collector/CollectorChildProcessWrapper.ts index 744c7b9..d2dca3a 100644 --- a/test/collector/CollectorChildProcessWrapper.ts +++ b/test/collector/CollectorChildProcessWrapper.ts @@ -27,4 +27,8 @@ export default class CollectorChildProcessWrapper extends ChildProcessWrapper { async fetchTelemetry() { return await collector().sendRequest({ command: 'telemetry' }); } + + async clear() { + await collector().sendRequest({ command: 'clear' }); + } } diff --git a/test/collector/Sink.ts b/test/collector/Sink.ts index 3b52db7..f7976fe 100644 --- a/test/collector/Sink.ts +++ b/test/collector/Sink.ts @@ -64,6 +64,14 @@ export default class Sink { return this.telemetry; } + clear() { + this.telemetry = { + traces: [], + metrics: [], + logs: [], + }; + } + printStats() { console.log(JSON.stringify(this.stats(), null, 2)); } diff --git a/test/collector/index.ts b/test/collector/index.ts index dc4baac..2a6445b 100644 --- a/test/collector/index.ts +++ b/test/collector/index.ts @@ -34,6 +34,9 @@ function registerIpcMessageListener() { case 'telemetry': sendToParentProcess({ id, ...sink.getTelemetry() }); break; + case 'clear': + sink.clear(); + break; default: console.error(`Unknown message: ${inspect(message)}`); } diff --git a/test/integration/rootHooks.ts b/test/integration/rootHooks.ts index da7dfcc..181ecda 100644 --- a/test/integration/rootHooks.ts +++ b/test/integration/rootHooks.ts @@ -21,6 +21,10 @@ export const mochaHooks = { console.debug('[rootHooks] global mock collector started'); }, + async beforeEach() { + collectorInstance.clear(); + }, + async afterAll() { console.debug('[rootHooks] stopping global mock collector'); await collectorInstance.stop(); diff --git a/test/integration/test.ts b/test/integration/test.ts index bef1c99..c2828bd 100644 --- a/test/integration/test.ts +++ b/test/integration/test.ts @@ -12,9 +12,12 @@ import runCommand from '../util/runCommand'; import waitUntil from '../util/waitUntil'; import ChildProcessWrapper, { defaultAppConfiguration } from './ChildProcessWrapper'; import { collector } from './rootHooks'; +import delay from '../util/delay'; const skipWhenNodeJsVersionIsSmallerThan = '18.0.0'; +const { fail } = expect; + const appPort = 1302; let expectedDistroVersion: number; @@ -104,7 +107,7 @@ describe('attach', () => { await appUnderTest.stop(); }); - it('should attach via --require and derive a service name from the package.json file ', async () => { + it('should attach via --require and derive a service name from the package.json file', async () => { await waitUntil(async () => { const telemetry = await waitForTelemetry(); expectMatchingSpan( @@ -122,6 +125,37 @@ describe('attach', () => { }); }); + describe('disable via DASH0_DISABLE', () => { + let appUnderTest: ChildProcessWrapper; + + before(async () => { + const appConfiguration = defaultAppConfiguration(appPort); + if (!appConfiguration.env) { + appConfiguration.env = {}; + } + appConfiguration.env.DASH0_DISABLE = 'true'; + appUnderTest = new ChildProcessWrapper(appConfiguration); + await appUnderTest.start(); + }); + + after(async () => { + await appUnderTest.stop(); + }); + + it('should do nothing if disabled', async () => { + await delay(1000); + const response = await fetch(`http://localhost:${appPort}/ohai`); + await delay(2000); + expect(response.status).to.equal(200); + const responsePayload = await response.json(); + expect(responsePayload).to.deep.equal({ message: 'We make Observability easy for every developer.' }); + + if (await collector().hasTelemetry()) { + fail('The collector received telemetry data although it should not have received anything.'); + } + }); + }); + async function waitForTelemetry() { const response = await fetch(`http://localhost:${appPort}/ohai`); expect(response.status).to.equal(200);