Skip to content

Commit

Permalink
feat: added env variable to require only specific libraries
Browse files Browse the repository at this point in the history
refs open-telemetry#3655

- added process.env.OTEL_REQUIRE_ONLY for e.g. b2b usages
- useful when you only want to use specific otel instrumentations
  • Loading branch information
kirrg001 committed Mar 10, 2023
1 parent ecb5ebe commit fd1e12c
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
## Unreleased

* feat: collect host id for non-cloud environments [#3575](https://github.com/open-telemetry/opentelemetry-js/pull/3575) @mwear
* feat: added env variable to require only specific libraries [#3666](https://github.com/open-telemetry/opentelemetry-js/pull/3666) @kirrg001

### :boom: Breaking Change

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const isMocha = [
* on the performance of instrumentation hooks being applied.
*/
export class RequireInTheMiddleSingleton {
private hook?: RequireInTheMiddle.Hooked;
private _moduleNameTrie: ModuleNameTrie = new ModuleNameTrie();
private static _instance?: RequireInTheMiddleSingleton;

Expand All @@ -59,9 +60,15 @@ export class RequireInTheMiddleSingleton {
}

private _initialize() {
RequireInTheMiddle(
// Intercept all `require` calls; we will filter the matching ones below
null,
// A list of strings separated by comma e.g. fastify,fs
const modules = process.env.OTEL_REQUIRE_ONLY
? process.env.OTEL_REQUIRE_ONLY.split(',').map(i => i.trim())
: null;

this.hook = RequireInTheMiddle(
// Intercept all `require` calls; we will filter the matching ones below.
// Alternatively you can set an env variable to only listen for specific libs.
modules,
{ internals: true },
(exports, name, basedir) => {
// For internal files on Windows, `name` will use backslash as the path separator
Expand All @@ -84,6 +91,15 @@ export class RequireInTheMiddleSingleton {
);
}

/**
* Deregister require-in-the-middle hook.
* @returns
*/
unhook() {
if (!this.hook) return;
this.hook.unhook();
}

/**
* Register a hook with `require-in-the-middle`
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import * as path from 'path';
import * as RequireInTheMiddle from 'require-in-the-middle';
import { RequireInTheMiddleSingleton } from '../../src/platform/node/RequireInTheMiddleSingleton';

const requireInTheMiddleSingleton = RequireInTheMiddleSingleton.getInstance();

type AugmentedExports = {
__ritmOnRequires?: string[];
};
Expand All @@ -34,15 +32,25 @@ const makeOnRequiresStub = (label: string): sinon.SinonStub =>
}) as RequireInTheMiddle.OnRequireFn);

describe('RequireInTheMiddleSingleton', () => {
describe('register', () => {
const onRequireFsStub = makeOnRequiresStub('fs');
const onRequireFsPromisesStub = makeOnRequiresStub('fs-promises');
const onRequireCodecovStub = makeOnRequiresStub('codecov');
const onRequireCodecovLibStub = makeOnRequiresStub('codecov-lib');
const onRequireCpxStub = makeOnRequiresStub('cpx');
const onRequireCpxLibStub = makeOnRequiresStub('cpx-lib');
describe('default', () => {
let requireInTheMiddleSingleton: RequireInTheMiddleSingleton;
let onRequireFsStub: sinon.SinonStub;
let onRequireFsPromisesStub: sinon.SinonStub;
let onRequireCodecovStub: sinon.SinonStub;
let onRequireCodecovLibStub: sinon.SinonStub;
let onRequireCpxStub: sinon.SinonStub;
let onRequireCpxLibStub: sinon.SinonStub;

before(() => {
onRequireFsStub = makeOnRequiresStub('fs');
onRequireFsPromisesStub = makeOnRequiresStub('fs-promises');
onRequireCodecovStub = makeOnRequiresStub('codecov');
onRequireCodecovLibStub = makeOnRequiresStub('codecov-lib');
onRequireCpxStub = makeOnRequiresStub('cpx');
onRequireCpxLibStub = makeOnRequiresStub('cpx-lib');

requireInTheMiddleSingleton = RequireInTheMiddleSingleton.getInstance();

requireInTheMiddleSingleton.register('fs', onRequireFsStub);
requireInTheMiddleSingleton.register(
'fs/promises',
Expand All @@ -69,6 +77,10 @@ describe('RequireInTheMiddleSingleton', () => {
onRequireCpxLibStub.resetHistory();
});

after(() => {
requireInTheMiddleSingleton.unhook();
});

it('should return a hooked object', () => {
const moduleName = 'm';
const onRequire = makeOnRequiresStub('m');
Expand Down Expand Up @@ -179,4 +191,71 @@ describe('RequireInTheMiddleSingleton', () => {
});
});
});

describe('with OTEL_REQUIRE_ONLY set', () => {
let requireInTheMiddleSingleton: RequireInTheMiddleSingleton;
let onRequireFsStub: sinon.SinonStub;
let onRequireCodecovStub: sinon.SinonStub;

describe('single module', function () {
before(() => {
onRequireFsStub = makeOnRequiresStub('fs');
onRequireCodecovStub = makeOnRequiresStub('codecov');

process.env.OTEL_REQUIRE_ONLY = 'fs';
requireInTheMiddleSingleton = RequireInTheMiddleSingleton.getInstance();

requireInTheMiddleSingleton.register('fs', onRequireFsStub);
requireInTheMiddleSingleton.register('codecov', onRequireCodecovStub);
});

beforeEach(() => {
onRequireFsStub.resetHistory();
onRequireCodecovStub.resetHistory();
});

after(() => {
delete process.env.OTEL_REQUIRE_ONLY;
requireInTheMiddleSingleton.unhook();
});

it('should call `onRequire` for fs', () => {
require('fs');
require('codecov');

assert.equal(onRequireFsStub.called, true);
assert.equal(onRequireCodecovStub.called, false);
});
});

describe('multiple modules', function () {
before(() => {
onRequireFsStub = makeOnRequiresStub('fs');
onRequireCodecovStub = makeOnRequiresStub('codecov');

process.env.OTEL_REQUIRE_ONLY = 'fs,codecov';
requireInTheMiddleSingleton = RequireInTheMiddleSingleton.getInstance();

requireInTheMiddleSingleton.register('fs', onRequireFsStub);
requireInTheMiddleSingleton.register('codecov', onRequireCodecovStub);
});

beforeEach(() => {
onRequireFsStub.resetHistory();
onRequireCodecovStub.resetHistory();
});

after(() => {
delete process.env.OTEL_REQUIRE_ONLY;
});

it('should call `onRequire` for codecov & fs', () => {
require('fs');
require('codecov');

assert.equal(onRequireFsStub.called, true);
assert.equal(onRequireCodecovStub.called, true);
});
});
});
});

0 comments on commit fd1e12c

Please sign in to comment.