-
Notifications
You must be signed in to change notification settings - Fork 1k
feat(browser otlp exporter): add fetch transport for fetch-only environments #5807
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
Changes from 30 commits
dd4ec25
e3cd53a
b722a83
c61c687
7994b96
1872256
14bdf0b
673af6f
008f175
65da6f9
6a3cbfb
0bd231b
fccddd4
bc4320a
ac93c9f
d63ab8e
23e7330
dd0b129
8a07ae1
4fad1df
27fe4a9
35d935e
82e013b
96bbff6
5530e4e
63e7a80
f9aeb0a
cfffa6a
daa5b39
bc12329
84f971e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| */ | ||
| import { ISerializer } from '@opentelemetry/otlp-transformer'; | ||
| import { | ||
| createOtlpFetchExportDelegate, | ||
| createOtlpSendBeaconExportDelegate, | ||
| createOtlpXhrExportDelegate, | ||
| } from '../otlp-browser-http-export-delegate'; | ||
|
|
@@ -35,17 +36,25 @@ export function createLegacyOtlpBrowserExportDelegate<Internal, Response>( | |
| signalResourcePath: string, | ||
| requiredHeaders: Record<string, string> | ||
| ): IOtlpExportDelegate<Internal> { | ||
| const useXhr = !!config.headers || typeof navigator.sendBeacon !== 'function'; | ||
| const createOtlpExportDelegate = inferExportDelegateToUse(config.headers); | ||
|
|
||
| const options = convertLegacyBrowserHttpOptions( | ||
| config, | ||
| signalResourcePath, | ||
| requiredHeaders | ||
| ); | ||
|
|
||
| if (useXhr) { | ||
| return createOtlpXhrExportDelegate(options, serializer); | ||
| return createOtlpExportDelegate(options, serializer); | ||
| } | ||
|
|
||
| export function inferExportDelegateToUse( | ||
| configHeaders: OTLPExporterConfigBase['headers'] | ||
| ) { | ||
| if (!configHeaders && typeof navigator.sendBeacon === 'function') { | ||
| return createOtlpSendBeaconExportDelegate; | ||
| } else if (typeof globalThis.fetch !== 'undefined') { | ||
| return createOtlpFetchExportDelegate; | ||
| } else { | ||
| return createOtlpSendBeaconExportDelegate(options, serializer); | ||
| return createOtlpXhrExportDelegate; | ||
| } | ||
| } | ||
|
Comment on lines
+50
to
60
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The former test I wrote was ineffective, every I added an intermediary testable function and updated the test. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /* | ||
| * 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 { IExporterTransport } from '../exporter-transport'; | ||
| import { ExportResponse } from '../export-response'; | ||
| import { diag } from '@opentelemetry/api'; | ||
| import { | ||
| isExportRetryable, | ||
| parseRetryAfterToMills, | ||
| } from '../is-export-retryable'; | ||
|
|
||
| export interface FetchTransportParameters { | ||
| url: string; | ||
| headers: () => Record<string, string>; | ||
| } | ||
|
|
||
| class FetchTransport implements IExporterTransport { | ||
| constructor(private _parameters: FetchTransportParameters) {} | ||
|
|
||
| async send(data: Uint8Array, timeoutMillis: number): Promise<ExportResponse> { | ||
| const abortController = new AbortController(); | ||
| const timeout = setTimeout(() => abortController.abort(), timeoutMillis); | ||
| try { | ||
| const isBrowserEnvironment = !!globalThis.location; | ||
| const url = new URL(this._parameters.url); | ||
| const response = await fetch(url.href, { | ||
| method: 'POST', | ||
| headers: this._parameters.headers(), | ||
| body: data, | ||
| signal: abortController.signal, | ||
| keepalive: isBrowserEnvironment, | ||
| mode: isBrowserEnvironment | ||
|
pichlermarc marked this conversation as resolved.
|
||
| ? globalThis.location?.origin === url.origin | ||
| ? 'same-origin' | ||
| : 'cors' | ||
|
SacDeNoeuds marked this conversation as resolved.
|
||
| : 'no-cors', | ||
| }); | ||
|
|
||
| if (response.status >= 200 && response.status <= 299) { | ||
| diag.debug('response success'); | ||
| return { status: 'success' }; | ||
| } else if (isExportRetryable(response.status)) { | ||
| const retryAfter = response.headers.get('Retry-After'); | ||
| const retryInMillis = parseRetryAfterToMills(retryAfter); | ||
| return { status: 'retryable', retryInMillis }; | ||
| } | ||
| return { | ||
| status: 'failure', | ||
| error: new Error('Fetch request failed with non-retryable status'), | ||
| }; | ||
| } catch (error) { | ||
| if (error?.name === 'AbortError') { | ||
| return { | ||
| status: 'failure', | ||
| error: new Error('Fetch request timed out', { cause: error }), | ||
| }; | ||
| } | ||
| return { | ||
| status: 'failure', | ||
| error: new Error('Fetch request errored', { cause: error }), | ||
| }; | ||
| } finally { | ||
| clearTimeout(timeout); | ||
| } | ||
| } | ||
|
|
||
| shutdown() { | ||
| // Intentionally left empty, nothing to do. | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Creates an exporter transport that uses `fetch` to send the data | ||
| * @param parameters applied to each request made by transport | ||
| */ | ||
| export function createFetchTransport( | ||
| parameters: FetchTransportParameters | ||
| ): IExporterTransport { | ||
| return new FetchTransport(parameters); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.