Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ feat(configuration): parse config for rc 3 [#6304](https://github.com/open-telem
### :bug: Bug Fixes

* fix(exporter-prometheus): add missing `@opentelemetry/semantic-conventions` dependency [#6330](https://github.com/open-telemetry/opentelemetry-js/pull/6330) @omizha
* fix(otlp-exporter-base): fix unwanted instrumentation of the fetch exports when context is not propagated [#6353](https://github.com/open-telemetry/opentelemetry-js/pull/6353) @david-luna

### :books: Documentation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,23 @@ class FetchTransport implements IExporterTransport {
async send(data: Uint8Array, timeoutMillis: number): Promise<ExportResponse> {
const abortController = new AbortController();
const timeout = setTimeout(() => abortController.abort(), timeoutMillis);
// Fetch API may be wrapped by an instrumentation lile `@opentelemetry/instrumentation-fetch`.
Comment thread
david-luna marked this conversation as resolved.
Outdated
// In that case the instrumentation would create a new Span for this request
// because the context manager cannot keep the context after `await` calls.
// This creates an indirect endless loop Export -> Span -> Export
// By using the `__original` function the instrumentation can't intercept the call
// and no Span will be created breaking the vicious cycle
let fetchApi = globalThis.fetch;
// @ts-expect-error -- fetch could be wrapped
if (typeof fetchApi.__original === 'function') {
// @ts-expect-error -- fetch could be wrapped
fetchApi = fetchApi.__original;
}

try {
const isBrowserEnvironment = !!globalThis.location;
const url = new URL(this._parameters.url);
const response = await fetch(url.href, {
const response = await fetchApi(url.href, {
method: 'POST',
headers: await this._parameters.headers(),
body: data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ describe('FetchTransport', function () {
});

describe('send', function () {
it('it uses global fetch API and is not affected by patching', function (done) {
// arrange
const fetchStub = sinon
.stub(globalThis, 'fetch')
.resolves(new Response('test response', { status: 200 }));
const transport = createFetchTransport(testTransportParameters);
// We patch fetch simulating what an instrumentation would do
const patchedStub = sinon.stub().callsFake(fetchStub);
globalThis.fetch = patchedStub;
(globalThis.fetch as any).__original = fetchStub;

//act
transport.send(testPayload, requestTimeout).then(response => {
// assert
try {
assert.strictEqual(response.status, 'success');
sinon.assert.notCalled(patchedStub);
sinon.assert.called(fetchStub);
} catch (e) {
done(e);
}
done();
}, done /* catch any rejections */);
});
it('returns success when request succeeds', function (done) {
// arrange
const fetchStub = sinon
Expand Down