Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(opencensus-shim) add require-in-the-middle hook to patch @opencensus/core #3809

Merged
merged 4 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ All notable changes to experimental packages in this project will be documented

## Unreleased

### :rocket: (Enhancement)

* feat(otlp-trace-exporters): Add User-Agent header to OTLP trace exporters. [#3790](https://github.com/open-telemetry/opentelemetry-js/pull/3790) @JamieDanielson

### :boom: Breaking Change

### :rocket: (Enhancement)

* feat(instrumentation): add ESM support for instrumentation. [#3698](https://github.com/open-telemetry/opentelemetry-js/pull/3698) @JamieDanielson, @pkanal, @vmarchaud, @lizthegrey, @bengl
* feat(otlp-trace-exporters): Add User-Agent header to OTLP trace exporters. [#3790](https://github.com/open-telemetry/opentelemetry-js/pull/3790) @JamieDanielson
dyladan marked this conversation as resolved.
Show resolved Hide resolved
* feat(opencensus-shim): add OpenCensus trace shim [#3809](https://github.com/open-telemetry/opentelemetry-js/pull/3809) @aabmass

### :bug: (Bug Fix)

Expand Down
7 changes: 3 additions & 4 deletions experimental/packages/shim-opencensus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,9 @@
"@opentelemetry/api": "^1.0.0"
},
"dependencies": {
"@opentelemetry/context-async-hooks": "1.13.0",
"@opentelemetry/core": "1.13.0",
"require-in-the-middle": "^6.0.0",
"semver": "^7.3.5"
"@opentelemetry/core": "^1.0.0",
aabmass marked this conversation as resolved.
Show resolved Hide resolved
"semver": "^7.3.5",
"require-in-the-middle": "^7.1.0"
aabmass marked this conversation as resolved.
Show resolved Hide resolved
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/shim-opencensus",
"sideEffects": false
Expand Down
19 changes: 19 additions & 0 deletions experimental/packages/shim-opencensus/src/register.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { installShim } from './shim';

installShim();
62 changes: 62 additions & 0 deletions experimental/packages/shim-opencensus/src/shim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { diag, trace, Tracer } from '@opentelemetry/api';
import { Hook } from 'require-in-the-middle';
import * as oc from '@opencensus/core';

import { ShimTracer } from './ShimTracer';
import { VERSION } from './version';

type CoreTracerConstructor = new (
...args: ConstructorParameters<typeof oc.CoreTracer>
) => oc.Tracer;

let hook: Hook | null = null;

interface OpenCensusShimConfig {
/**
* An optional OpenTelemetry tracer to send OpenCensus spans to. If not provided, one will be
* created for you.
*/
tracer?: Tracer | undefined;
}

/**
* Patches OpenCensus to redirect all instrumentation to OpenTelemetry. Uses
* require-in-the-middle to override the implementation of OpenCensus's CoreTracer.
*
* Use {@link uninstallShim} to undo the effects of this function.
*
* @param config
*/
export function installShim({
tracer = trace.getTracer('@opentelemetry/shim-opencensus', VERSION),
}: OpenCensusShimConfig = {}): void {
diag.info('Installing OpenCensus shim require-in-the-middle hook');

hook = new Hook(['@opencensus/core'], exports => {
Flarna marked this conversation as resolved.
Show resolved Hide resolved
const CoreTracer: CoreTracerConstructor = ShimTracer.bind(null, tracer);
return {
...exports,
CoreTracer,
};
});
}

export function uninstallShim(): void {
hook?.unhook();
}
72 changes: 72 additions & 0 deletions experimental/packages/shim-opencensus/test/shim.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as assert from 'assert';
import { installShim, uninstallShim } from '../src/shim';
import { ShimTracer } from '../src';
import { CoreTracer as OrigCoreTracer } from '@opencensus/core';
import { withTestTracerProvider } from './util';
import { trace } from '@opentelemetry/api';

describe('shim', () => {
beforeEach(uninstallShim);
afterEach(uninstallShim);
afterEach(() => {
trace.disable();
});

describe('installShim', () => {
it('should patch the @opencensus/core CoreTracer to create instances of the ShimTracer', () => {
installShim();
const { CoreTracer } = require('@opencensus/core');
assert.notStrictEqual(CoreTracer, OrigCoreTracer);
assert(new CoreTracer() instanceof ShimTracer);
});

it('should use the provided Tracer', async () => {
const spans = await withTestTracerProvider(tracerProvider => {
const tracer = tracerProvider.getTracer('test');
installShim({ tracer });
const CoreTracer: typeof OrigCoreTracer =
require('@opencensus/core').CoreTracer;
const coreTracer = new CoreTracer();
coreTracer.startChildSpan().end();
});
assert.strictEqual(spans.length, 1);
});

it('should use the global OpenTelemetry TracerProvider if none provided', async () => {
installShim();
const spans = await withTestTracerProvider(tracerProvider => {
trace.setGlobalTracerProvider(tracerProvider);
const CoreTracer: typeof OrigCoreTracer =
require('@opencensus/core').CoreTracer;
const coreTracer = new CoreTracer();
coreTracer.startChildSpan().end();
});
assert.strictEqual(spans.length, 1);
});
});

describe('uninstallShim', () => {
it('should restore the original CoreTracer', () => {
installShim();
uninstallShim();
const { CoreTracer } = require('@opencensus/core');
assert.strictEqual(CoreTracer, OrigCoreTracer);
});
});
});
18 changes: 13 additions & 5 deletions experimental/packages/shim-opencensus/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,29 @@ import {
AsyncHooksContextManager,
AsyncLocalStorageContextManager,
} from '@opentelemetry/context-async-hooks';
import { Tracer, context } from '@opentelemetry/api';
import { Tracer, TracerProvider, context } from '@opentelemetry/api';

export async function withTestTracer(
func: (shimTracer: ShimTracer, otelTracer: Tracer) => void | Promise<void>
): Promise<ReadableSpan[]> {
return await withTestTracerProvider(tracerProvider =>
func(
new ShimTracer(tracerProvider.getTracer('test-shim')),
tracerProvider.getTracer('test-otel')
)
);
}

export async function withTestTracerProvider(
func: (otelTracerProvider: TracerProvider) => void | Promise<void>
): Promise<ReadableSpan[]> {
const tracerProvider = new BasicTracerProvider({
sampler: new AlwaysOnSampler(),
});
const inMemExporter = new InMemorySpanExporter();
tracerProvider.addSpanProcessor(new SimpleSpanProcessor(inMemExporter));

await func(
new ShimTracer(tracerProvider.getTracer('test-shim')),
tracerProvider.getTracer('test-otel')
);
await func(tracerProvider);

await tracerProvider.forceFlush();
const spans = inMemExporter.getFinishedSpans();
Expand Down