Skip to content

fix(sdk-node): fail-fast on LoggerProvider creation from config#6785

Merged
trentm merged 12 commits into
open-telemetry:mainfrom
trentm:trentm-declconf-create-play
Jun 17, 2026
Merged

fix(sdk-node): fail-fast on LoggerProvider creation from config#6785
trentm merged 12 commits into
open-telemetry:mainfrom
trentm:trentm-declconf-create-play

Conversation

@trentm

@trentm trentm commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

This PR includes a few changes to declarative config "create()" handling in startNodeSDK().
I've started with just the config handling of logger_provider to have a smaller start and smaller diff for review.

  1. This starts a move to "fail fast" semantics: If there is a problem creating SDK components from the parsed config, then create() throws, and startNodeSDK() warns and returns a no-op SDK. This matches OTel Java behaviour and the spec. From https://opentelemetry.io/docs/specs/otel/configuration/sdk/#create

This SHOULD return an error if it encounters an error in configuration (i.e. fail fast) in accordance with initialization error handling principles.

  1. I'm proposing a naming pattern:
    create<SDK thing>FromConfig()   # e.g., createLogRecordExporterFromConfig

for the suite of functions that create an SDK thing from configuration data.
"create" because these are all used by the SDK configuration "create()" step (https://opentelemetry.io/docs/specs/otel/configuration/sdk/#create).
"FromConfig" because it is shorter than "FromConfiguration", and these functions don't always take a full ConfigurationModel.

Currently we have these patterns:

    get<SDK thing>                    # getLogRecordExporter
    get<SDK thing>FromConfiguration   # getSpanProcessorsFromConfiguration
    build<SDK thing>FromConfig        # buildSamplerFromConfig
  1. This fixes missing handling of logger_provider.limits, which were previously not being passed to the new LoggerProvider(...).

  2. I've added a checkConfigUse(...) internal function that can help warn about unhandled config properties in create<SDK thing>FromConfig() functions. It is pretty low tech.
    With this config:

logger_provider:
  logger_configurator/development:
    default_config:
      enabled: true
  processors:
    - simple:
        exporter:
          console:

Before: this would silently ignore "logger_configurator/development".
After: it diag.warn's

Config warning: some specified LoggerProvider configuration properties were not handled by SDK setup: ["logger_configurator/development"]

This PR includes a few changes to declarative config "create()"
handling in startNodeSDK().
I've started with just the config handling of `logger_provider`
to have a smaller start and smaller diff for review.

First, this *starts* a move to "fail fast" semantics: If there is a
problem creating SDK components from the parsed config, then `create()`
throws, and startNodeSDK() warns and returns a no-op SDK. This matches
OTel Java behaviour and the spec. From
https://opentelemetry.io/docs/specs/otel/configuration/sdk/#create

> This SHOULD return an error if it encounters an error in configuration (i.e. fail fast) in accordance with initialization error handling principles.

Second, I'm proposing a naming pattern:
    create<SDK thing>FromConfig()   # e.g., createLogRecordExporterFromConfig
for the suite of functions that create an SDK thing from configuration
data. "create" because these are all used by the SDK configuration
"create()" step
(https://opentelemetry.io/docs/specs/otel/configuration/sdk/#create).
"FromConfig" because it is shorter than "FromConfiguration", and
these functions don't always take a full `ConfigurationModel`.

Currently we have these patterns:
    get<SDK thing>                    # getLogRecordExporter
    get<SDK thing>FromConfiguration   # getSpanProcessorsFromConfiguration
    build<SDK thing>FromConfig        # buildSamplerFromConfig

Third, this fixes missing handling of `logger_provider.limits`, which
were previously not being passed to the new LoggerProvider(...).

Last, I've added a `checkConfigUse(...)` internal function that can help
warn about unhandled config properties in `create<SDK thing>FromConfig()`
functions. It is pretty low tech. With this config:

```yaml
logger_provider:
  logger_configurator/development:
    default_config:
      enabled: true
  processors:
    - simple:
        exporter:
          console:
```

Before: this would silently ignore "logger_configurator/development".
After: it diag.warn's

```
Config warning: some specified LoggerProvider configuration properties were not handled by SDK setup: ["logger_configurator/development"]
```
@codecov

codecov Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.03540% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.93%. Comparing base (940eb20) to head (7458520).

Files with missing lines Patch % Lines
...ental/packages/opentelemetry-sdk-node/src/utils.ts 91.78% 6 Missing ⚠️
...ental/packages/opentelemetry-sdk-node/src/start.ts 92.50% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6785      +/-   ##
==========================================
- Coverage   94.97%   94.93%   -0.04%     
==========================================
  Files         383      383              
  Lines       12968    13007      +39     
  Branches     2961     2974      +13     
==========================================
+ Hits        12316    12348      +32     
- Misses        652      659       +7     
Files with missing lines Coverage Δ
...ental/packages/opentelemetry-sdk-node/src/start.ts 97.05% <92.50%> (-2.95%) ⬇️
...ental/packages/opentelemetry-sdk-node/src/utils.ts 96.50% <91.78%> (-0.52%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trentm

trentm commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

4. I've added a checkConfigUse(...) internal function [...]
it diag.warn's

Arguably this could be made to throw per the "fail fast" policy.

@trentm
trentm marked this pull request as ready for review June 4, 2026 21:16
@trentm
trentm requested a review from a team as a code owner June 4, 2026 21:16
readers: meterReaders,
views: meterViews ?? [],
});
components.meterProvider = meterProvider;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

to confirm (as per your PR description), do you plan on opening following PRs to update here to createMeterProviderFromConfig and below a createTracerProviderFromConfig?
if your plan is to do this right after, then fine, otherwise make sure you open an issue so is not forgotten :)

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.

Yes, definitely. I wanted to start with just one in case discussion/review suggested significant changes.


export interface SDKComponents {
contextManager: ContextManager;
contextManager?: ContextManager;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

on the existing sdk start parameters (NodeSDKConfiguration) the contextManager is required, so I followed that. Any reason why now should be optional?

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.

Making all the SDKComponents properties optional was necessary (without some coding pain) to support this change where components = {} is created outside the try { ... } so it can be used inside the catch { ... }:

  const components: SDKComponents = {};

  try {
    components.contextManager = new AsyncLocalStorageContextManager();
    components.contextManager.enable();
    ...
  } catch (err) {
     // ... use `components` here for cleanup
  }

Interface SDKComponents is only used for the return type of the internal create() function, so there is no breaking change for the user here.

@trentm
trentm requested a review from maryliag June 15, 2026 20:52

@MikeGoldsmith MikeGoldsmith left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looking good, thanks @trentm.

return new BatchLogRecordProcessor(exporter, {
maxQueueSize: props.max_queue_size ?? undefined,
maxExportBatchSize: props.max_export_batch_size ?? undefined,
scheduledDelayMillis: props.schedule_delay ?? undefined,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We've lost the default of 1000ms here.

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.

Yes, see #6796

* configuration during `create()` and watches for untouched properties
* might be nice.)
*/
function checkConfigUse(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this also throw like the mustSingleEntry func?

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.

Thanks for the review. I went back and forth on this and settled on not throwing, at least for now.

Say a future v1.2.0 of the configuration spec allows a new property for attribute_limits, and assuming the guard on exact file_format values changes to allow future v1.x versions. Do we want declarative config file handing to completely fail if that new attribute limit isn't handled yet by the current sdk-node package? I realize this is theoretical because the current configuration handling doesn't do semver-based handling of the file_format.

Happy to change to throwing here.

@trentm
trentm requested a review from MikeGoldsmith June 16, 2026 22:02
@trentm
trentm added this pull request to the merge queue Jun 17, 2026
Merged via the queue into open-telemetry:main with commit d70e7df Jun 17, 2026
31 checks passed
@trentm
trentm deleted the trentm-declconf-create-play branch June 17, 2026 18:35
MikeGoldsmith added a commit to MikeGoldsmith/opentelemetry-js that referenced this pull request Jun 30, 2026
Remove the EXPERIMENTAL_SAMPLER_KEYS list and the dedicated warn branch.
Unrecognized sampler types (including known experimentals like
jaeger_remote/development) now fall through to a single
diag.warn + ParentBased(AlwaysOn) default. Saves a maintenance touch
point against the upstream schema and aligns with open-telemetry#6785's direction.
@otelbot-js otelbot-js Bot mentioned this pull request Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

3 participants