Skip to content

feat(sdk): validate all export URLs before starting the SDK - #357

Open
mquentin wants to merge 11 commits into
open-telemetry:mainfrom
mquentin:mquentin/sdk_export_url_validation
Open

feat(sdk): validate all export URLs before starting the SDK#357
mquentin wants to merge 11 commits into
open-telemetry:mainfrom
mquentin:mquentin/sdk_export_url_validation

Conversation

@mquentin

Copy link
Copy Markdown
Contributor

What

Following this comment of a previous and merged PR:
#346 (comment)

The SDK now validates every OTLP export URL (root and per-signal) before
starting — an invalid URL logs a diag.error and returns a no-op SDK instead of
silently dropping telemetry.

Why

Only the root URL was validated. Invalid per-signal URLs just skipped the
exporter, so with custom processors the SDK reported success while exporting
nothing. This moves the check into the SDK so the sandbox's manual guard is no
longer needed.

Changes

  • core/exportUrl.ts (new): parseExportUrl() helper.
  • core/sdk.ts: validate signal URLs up-front, bail to NOOP_SDK before starting
    either signal; unset URLs inherit the root endpoint.
  • traces/logs SDKs: invalid URL returns NOOP_SDK instead of silently
    skipping the exporter.
  • sandbox/src/otel.ts: removed the redundant guard.

Comment thread packages/sdk/src/core/sdk.ts Outdated
type CombinedConfig = RootConfig & {
logs?: RemoveCommonProps<LogsConfig>;
traces?: RemoveCommonProps<TracesConfig>;
};

@mquentin mquentin Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second commit of the PR (refactor(sdk): drop signal-config casts in combineSdks) goal is to prevent having dangerous casting here such as

    const signalExportUrls: [string, string | undefined][] = [
      ['Logs SDK', (config?.logs as LogsConfig | undefined)?.exportConfig?.url],
      [
        'Traces SDK',
        (config?.traces as TracesConfig | undefined)?.exportConfig?.url,
      ],
    ];

I will bring the point to the SIG

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully get here about the dangerous casting. However I'm not opposed to use a stricter type here

The intent of ExtractConfigs<T> was to allow users of the combineSdks add extra SDKs if they se it fit. So the following code is typed

const startCustomSdk = (config: CustomConfig ) => {
  // return `WebSdk` object
}

// Make SDK composition
const startBrowserSdkWithCustom = combineSdks({
  traces: startTracesSdk,
  logs: startLogsSdk,
  custom: startCustomSdk,
});

// now the combined function has `custom` as property of the config type the user defined
startBrowserSdkWithCustom({
  serviceName: 'foo',
  traces: { /**/ },
  logs: { /**/ },
  custom: { /**/ }, // <- the editor provides type autocompletion for this
});

With the CombinedConfig we have to maintain it manually and update if necessary.

Now is see the combineSdks function is not exported. IMHO this limits the user to only the SDKs we provide here (logs, traces and both). There is always the option of telling users to create a wrapper function around the start*Sdk functions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: the new type makes sense since the combine function only looks for logs and traces properties. The logic of the method is only resolving the common config properties before calling the factory function. I think this could be done in a loop so any given SDK factory function by the user will be called too.

I guess the question we should ask is. Should we expose the combineSdks function?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully get here about the dangerous casting.

I was talking about each of the config?.logs as LogsConfig

I guess the question we should ask is. Should we expose the combineSdks function?

Could be a good topic for the SIG

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be a good topic for the SIG

Added

@mquentin
mquentin marked this pull request as ready for review July 20, 2026 12:57
@mquentin
mquentin requested a review from a team as a code owner July 20, 2026 12:57
@mquentin

Copy link
Copy Markdown
Contributor Author

Related to the SIG discussion about enabling Traces if the log URL is the only erroneous URL and enabling the Logs if the trace URL is the only erroneous URL, it makes quite some changes in the SDK:

mquentin#1

I suggest we do not proceed with such an impactful change and keep it simple for now: if any URL is erroneous we return a fast NOOP_SDK which is the recommended solution of Trent Mick

@david-luna

Copy link
Copy Markdown
Contributor

Related to the SIG discussion about enabling Traces if the log URL is the only erroneous URL and enabling the Logs if the trace URL is the only erroneous URL, it makes quite some changes in the SDK:

mquentin#1

I suggest we do not proceed with such an impactful change and keep it simple for now: if any URL is erroneous we return a fast NOOP_SDK which is the recommended solution of Trent Mick

For completeness I would add this aligns with the NodeSDK behavior with declarative configuration. I also think is a good idea to behave the same way so we do not confuse dev that instrument both frontend and backend

Comment thread packages/sdk/src/core/sdk.ts

@david-luna david-luna left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I'd wait a bit for other approvers to give feedback befor merge.

Comment thread packages/sdk/src/core/exportUrl.ts
Comment thread packages/sdk/src/core/sdk.ts Outdated
Comment thread packages/sdk/src/startBrowserSdk.test.ts
Comment thread packages/sdk/src/startBrowserSdk.test.ts Outdated
Comment thread sandbox/src/otel.ts
Comment thread packages/sdk/README.md Outdated
mquentin and others added 7 commits August 4, 2026 10:26
Co-authored-by: Jared Freeze <overbalance@users.noreply.github.com>
Co-authored-by: Jared Freeze <overbalance@users.noreply.github.com>
Co-authored-by: Jared Freeze <overbalance@users.noreply.github.com>
Co-authored-by: Jared Freeze <overbalance@users.noreply.github.com>
Co-authored-by: Jared Freeze <overbalance@users.noreply.github.com>
The processors docs claimed that setting `processors` makes the SDK
ignore `exportConfig`, but the code (`!config?.processors ||
config?.exportConfig`) still honors it: setting both appends an OTLP
batch exporter alongside the custom processors. Corrected the
LogsConfig/TracesConfig JSDoc, both README processors sections, and the
combineSdks propagation comments, and fixed the stale `processorConfig`
reference (the field is `batchProcessorConfig`).
@mquentin

mquentin commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

So @overbalance to address both of you feedbacks I introduced two commits:

@david-luna

Copy link
Copy Markdown
Contributor

@mquentin could you fix the merge conflict?

@mquentin

Copy link
Copy Markdown
Contributor Author

@mquentin could you fix the merge conflict?

@david-luna sorry for the delay, here is the fix pushed

* (that is not an error). Callers can check this to surface a
* misconfiguration, e.g. `if (sdk.invalidConfig) { throw ... }`.
*/
invalidConfig?: boolean;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we think that in the future we might have something else triggering a failure in SDK start that is not config related? I can't think of an example right now but I'm wondering if we would cage ourselves with this name and force us to change it in the future or add another flag for a different kind of start up failure

Maybe we can rename it something more generic like startFailed or just failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants