class SpanBuilderSdk implements Span.Builder {

  @Override
  public Span startSpan() {
    final Context parentContext =
        isRootSpan ? Context.root() : parent == null ? Context.current() : parent;
    final Span parentSpan = TracingContextUtils.getSpan(parentContext);
    final SpanContext parentSpanContext = parentSpan.getContext();
    String traceId;
    String spanId = idsGenerator.generateSpanId();
    TraceState traceState = TraceState.getDefault();
    if (!parentSpanContext.isValid()) {
      // New root span.
      traceId = idsGenerator.generateTraceId();
    } else {
      // New child span.
      traceId = parentSpanContext.getTraceIdAsHexString();
      traceState = parentSpanContext.getTraceState();
    }
    List<SpanData.Link> immutableLinks =
        links == null ? Collections.emptyList() : Collections.unmodifiableList(links);
    // Avoid any possibility to modify the links list by adding links to the Builder after the
    // startSpan is called. If that happens all the links will be added in a new list.
    links = null;
    ReadableAttributes immutableAttributes = attributes == null ? Attributes.empty() : attributes;
    SamplingResult samplingResult =
        traceConfig
            .getSampler()
            .shouldSample(
                parentSpanContext,
                traceId,
                spanName,
                spanKind,
                immutableAttributes,
                immutableLinks);
    Sampler.Decision samplingDecision = samplingResult.getDecision();

    SpanContext spanContext =
        createSpanContext(traceId, spanId, traceState, Samplers.isSampled(samplingDecision));

    if (!Samplers.isRecording(samplingDecision)) {
      return DefaultSpan.create(spanContext);
    }
    ReadableAttributes samplingAttributes = samplingResult.getAttributes();
    if (!samplingAttributes.isEmpty()) {
      if (attributes == null) {
        attributes = new AttributesMap(traceConfig.getMaxNumberOfAttributes());
      }
      samplingAttributes.forEach(
          new AttributeConsumer() {
            @Override
            public <T> void consume(AttributeKey<T> key, T value) {
              attributes.put(key, value);
            }
          });
    }

    // Avoid any possibility to modify the attributes by adding attributes to the Builder after the
    // startSpan is called. If that happens all the attributes will be added in a new map.
    AttributesMap recordedAttributes = attributes;
    attributes = null;

    return RecordEventsReadableSpan.startSpan(
        spanContext,
        spanName,
        instrumentationLibraryInfo,
        spanKind,
        parentSpanContext.getSpanIdAsHexString(),
        parentSpanContext.isRemote(),
        traceConfig,
        spanProcessor,
        getClock(parentSpan, clock),
        resource,
        recordedAttributes,
        immutableLinks,
        totalNumberOfLinksAdded,
        startEpochNanos);
  }

    SpanBuilderSdk(
      String spanName,
      InstrumentationLibraryInfo instrumentationLibraryInfo,
      SpanProcessor spanProcessor,
      TraceConfig traceConfig,
      Resource resource,
      IdsGenerator idsGenerator,
      Clock clock);

}