Repository: open-telemetry/opentelemetry-java
File: sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java (Java)

Code before:
    return tracerBuilder(instrumentationScopeName)
        .setInstrumentationVersion(instrumentationScopeVersion)
        .build();
  }

  @Override
  public TracerBuilder tracerBuilder(@Nullable String instrumentationScopeName) {
    // Per the spec, both null and empty are "invalid" and a default value should be used.
    if (instrumentationScopeName == null || instrumentationScopeName.isEmpty()) {
      logger.fine("Tracer requested without instrumentation scope name.");
      instrumentationScopeName = DEFAULT_TRACER_NAME;
    }
    return new SdkTracerBuilder(tracerSdkComponentRegistry, instrumentationScopeName);
  }

  /** Returns the {@link SpanLimits} that are currently applied to created spans. */
  public SpanLimits getSpanLimits() {
    return sharedState.getSpanLimits();
  }

  /** Returns the configured {@link Sampler}. */
  public Sampler getSampler() {
    return sharedState.getSampler();
  }

  // currently not public as experimental
  void setScopeConfigurator(ScopeConfigurator<TracerConfig> scopeConfigurator) {
    this.tracerConfigurator = scopeConfigurator;
    this.tracerSdkComponentRegistry
        .getComponents()
        .forEach(
            sdkTracer ->
                sdkTracer.updateTracerConfig(
                    getTracerConfig(sdkTracer.getInstrumentationScopeInfo())));
  }

  /**
   * Attempts to stop all the activity for {@link Tracer}s created by this provider. Calls {@link
   * SpanProcessor#shutdown()} for all registered {@link SpanProcessor}s.
   *
   * <p>The returned {@link CompletableResultCode} will be completed when all the Spans are
   * processed.
   *
   * <p>After this is called, newly created {@code Span}s will be no-ops.
   *
   * <p>After this is called, further attempts at re-using this instance will result in undefined
   * behavior. It should be considered a terminal operation for the SDK.
   *
   * @return a {@link CompletableResultCode} which is completed when all the span processors have
   *     been shut down.
   */

Review comment (refactor):
The pattern for giving access to these experimental features has been via `Sdk{Signal}ProviderUtil`, a public class in an internal package, with static helper methods for reflectively accessing package private methods.

For tracing, this is `SdkTracerProviderUtil`.

I'd recommend adding an accessor method there as part of this PR. If you do, please add javadoc to this pointing to that method.

If you choose to punt on that, let's add a TODO to followup:
```suggestion
  // TODO: add public experimental accessor in SdkTracerProviderUtil
```

Speaking of followups, after landing this, should open an issue to track extending metrics and logs with the same capability. 

Code after:
  public Tracer get(String instrumentationScopeName, String instrumentationScopeVersion) {
    return tracerBuilder(instrumentationScopeName)
        .setInstrumentationVersion(instrumentationScopeVersion)
        .build();
  }

  @Override
  public TracerBuilder tracerBuilder(@Nullable String instrumentationScopeName) {
    // Per the spec, both null and empty are "invalid" and a default value should be used.
    if (instrumentationScopeName == null || instrumentationScopeName.isEmpty()) {
      logger.fine("Tracer requested without instrumentation scope name.");
      instrumentationScopeName = DEFAULT_TRACER_NAME;
    }
    return new SdkTracerBuilder(tracerSdkComponentRegistry, instrumentationScopeName);
  }

  /** Returns the {@link SpanLimits} that are currently applied to created spans. */
  public SpanLimits getSpanLimits() {
    return sharedState.getSpanLimits();
  }

  /** Returns the configured {@link Sampler}. */
  public Sampler getSampler() {
    return sharedState.getSampler();
  }

  /**
   * Updates the tracer configurator, which computes {@link TracerConfig} for each {@link
   * InstrumentationScopeInfo}.
   *
   * <p>This method is experimental so not public. You may reflectively call it using {@link
   * SdkTracerProviderUtil#setTracerConfigurator(SdkTracerProvider, ScopeConfigurator)}.
   *
   * @see TracerConfig#configuratorBuilder()
   */
  void setTracerConfigurator(ScopeConfigurator<TracerConfig> tracerConfigurator) {
    this.tracerConfigurator = tracerConfigurator;
    this.tracerSdkComponentRegistry
        .getComponents()
        .forEach(
            sdkTracer ->
                sdkTracer.updateTracerConfig(
                    getTracerConfig(sdkTracer.getInstrumentationScopeInfo())));
  }

  /**
   * Attempts to stop all the activity for {@link Tracer}s created by this provider. Calls {@link
   * SpanProcessor#shutdown()} for all registered {@link SpanProcessor}s.
   *
   * <p>The returned {@link CompletableResultCode} will be completed when all the Spans are
   * processed.