Exemple #1
0
        public void StartSpanFrom_Recorded_ParentSpan()
        {
            var tracer = (Tracer)tracerFactory.GetTracer("foo", "semver:1.0.0");

            var traceState = new List <KeyValuePair <string, string> > {
                new KeyValuePair <string, string>("k1", "v1")
            };
            var grandParentContext = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded, traceState);
            var parentSpan         = (Span)tracer.StartSpan(SpanName, grandParentContext);

            var startTimestamp = PreciseTimestamp.GetUtcNow();
            var span           = (Span)tracer.StartSpan(SpanName, parentSpan);

            Assert.True(span.Context.IsValid);
            Assert.Equal(parentSpan.Context.TraceId, span.Context.TraceId);
            Assert.Equal(span.Activity.SpanId, span.Context.SpanId);
            Assert.Equal(parentSpan.Context.SpanId, span.ParentSpanId);
            Assert.Equal(parentSpan.Context.TraceOptions, span.Context.TraceOptions);
            Assert.Same(traceState, span.Context.Tracestate);

            Assert.True(span.IsRecordingEvents);
            Assert.Equal(SpanKind.Internal, span.Kind);
            AssertApproxSameTimestamp(startTimestamp, span.StartTimestamp);
            Assert.Empty(span.Links);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="SamplingPercentageEstimatorTelemetryProcessor"/> class.
        /// <param name="settings">Dynamic sampling estimator settings.</param>
        /// <param name="callback">Callback to invoke every time sampling percentage is evaluated.</param>
        /// <param name="next">Next TelemetryProcessor in call chain.</param>
        /// </summary>
        public SamplingPercentageEstimatorTelemetryProcessor(
            Channel.Implementation.SamplingPercentageEstimatorSettings settings,
            Channel.Implementation.AdaptiveSamplingPercentageEvaluatedCallback callback,
            ITelemetryProcessor next)
        {
            this.evaluationCallback = callback;
            this.settings           = settings ?? throw new ArgumentNullException(nameof(settings));
            this.next = next ?? throw new ArgumentNullException(nameof(next));

            this.CurrentSamplingRate          = settings.EffectiveInitialSamplingRate;
            this.CurrentProactiveSamplingRate = settings.EffectiveInitialSamplingRate;

            this.itemCount = new ExponentialMovingAverageCounter(settings.EffectiveMovingAverageRatio);
            this.proactivelySampledInCount = new ExponentialMovingAverageCounter(settings.EffectiveMovingAverageRatio);

            this.samplingPercentageLastChangeDateTime = PreciseTimestamp.GetUtcNow();

            // set evaluation interval to default value if it is negative or zero
            this.evaluationInterval = this.settings.EffectiveEvaluationInterval;

            // set up timer to run math to estimate sampling percentage
            this.evaluationTimer = new Timer(
                this.EstimateSamplingPercentage,
                null,
                this.evaluationInterval,
                this.evaluationInterval);
        }
        /// <inheritdoc/>
        public void AddEvent(string name, IDictionary <string, object> eventAttributes)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (eventAttributes == null)
            {
                throw new ArgumentNullException(nameof(eventAttributes));
            }

            if (!this.IsRecordingEvents)
            {
                return;
            }

            lock (this.@lock)
            {
                if (this.HasEnded)
                {
                    // logger.log(Level.FINE, "Calling AddEvent() on an ended Span.");
                    return;
                }

                this.InitializedEvents.AddEvent(TimedEvent <IEvent> .Create(PreciseTimestamp.GetUtcNow(), Event.Create(name, eventAttributes)));
            }
        }
        public async Task DroppingEvents()
        {
            var maxNumberOfEvents = 8;
            var traceConfig       = new TracerConfiguration(32, maxNumberOfEvents, 32);
            var tracer            = TracerFactory.Create(b => b
                                                         .AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor))
                                                         .SetTracerOptions(traceConfig)
                                                         .SetSampler(new AlwaysSampleSampler()))
                                    .GetTracer(null);

            var span = (Span)tracer.StartRootSpan(SpanName);

            var eventTimestamps = new DateTimeOffset[2 * maxNumberOfEvents];

            for (int i = 0; i < 2 * maxNumberOfEvents; i++)
            {
                eventTimestamps[i] = PreciseTimestamp.GetUtcNow();
                span.AddEvent(new Event("foo", eventTimestamps[i]));
                await Task.Delay(10);
            }

            Assert.Equal(maxNumberOfEvents, span.Events.Count());

            var events = span.Events.ToArray();

            for (int i = 0; i < maxNumberOfEvents; i++)
            {
                Assert.Equal(eventTimestamps[i + maxNumberOfEvents], events[i].Timestamp);
            }

            span.End();

            Assert.Equal(maxNumberOfEvents, span.Events.Count());
        }
        public void ProcessorDoesNotBlockOnExporter()
        {
            spanExporter = new TestExporter(_ => Thread.Sleep(500));

            spanProcessor = new BatchingSpanProcessor(spanExporter);

            var sampledActivity = new Activity("foo");

            sampledActivity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
            sampledActivity.SetIdFormat(ActivityIdFormat.W3C);
            sampledActivity.Start();
            var span =
                new Span(
                    sampledActivity,
                    Tracestate.Empty,
                    SpanKind.Internal,
                    TraceConfig.Default,
                    spanProcessor,
                    PreciseTimestamp.GetUtcNow(),
                    default);

            // does not block
            var sw = Stopwatch.StartNew();

            span.End();
            sw.Stop();

            Assert.InRange(sw.Elapsed, TimeSpan.Zero, TimeSpan.FromMilliseconds(100));

            var exported = WaitForSpans(spanExporter, 1, TimeSpan.FromMilliseconds(600));

            Assert.Single(exported);
        }
Exemple #6
0
        /// <inheritdoc/>
        public void AddEvent(string name, IDictionary <string, object> eventAttributes)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (eventAttributes == null)
            {
                throw new ArgumentNullException(nameof(eventAttributes));
            }

            if (!this.IsRecordingEvents)
            {
                return;
            }

            lock (this.@lock)
            {
                if (this.HasEnded)
                {
                    // logger.log(Level.FINE, "Calling AddEvent() on an ended Span.");
                    return;
                }

                if (this.events == null)
                {
                    this.events =
                        new EvictingQueue <Event>(this.tracerConfiguration.MaxNumberOfEvents);
                }

                this.events.AddEvent(new Event(name, PreciseTimestamp.GetUtcNow(), eventAttributes));
            }
        }
Exemple #7
0
        /// <inheritdoc/>
        public void AddEvent(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (!this.IsRecordingEvents)
            {
                return;
            }

            lock (this.@lock)
            {
                if (this.HasEnded)
                {
                    // logger.log(Level.FINE, "Calling AddEvent() on an ended Span.");
                    return;
                }

                if (this.events == null)
                {
                    this.events =
                        new EvictingQueue <IEvent>(this.traceConfig.MaxNumberOfEvents);
                }

                this.events.AddEvent(Event.Create(name, PreciseTimestamp.GetUtcNow()));
            }
        }
Exemple #8
0
        private Span(
            string name,
            SpanContext parentSpanContext,
            ActivityAndTracestate activityAndTracestate,
            bool ownsActivity,
            SpanKind spanKind,
            SpanCreationOptions spanCreationOptions,
            TracerConfiguration tracerConfiguration,
            SpanProcessor spanProcessor,
            Resource libraryResource)
        {
            this.Name            = name;
            this.LibraryResource = libraryResource;

            IEnumerable <Link> links = null;

            if (spanCreationOptions != null)
            {
                links = spanCreationOptions.Links ?? spanCreationOptions.LinksFactory?.Invoke();
                this.startTimestamp = spanCreationOptions.StartTimestamp;
            }

            if (this.startTimestamp == default)
            {
                this.startTimestamp = PreciseTimestamp.GetUtcNow();
            }

            this.tracerConfiguration = tracerConfiguration;
            this.spanProcessor       = spanProcessor;
            this.Kind         = spanKind;
            this.OwnsActivity = ownsActivity;
            this.Activity     = activityAndTracestate.Activity;

            var tracestate = activityAndTracestate.Tracestate;

            this.IsRecording = MakeSamplingDecision(
                parentSpanContext,
                name,
                null,
                links, // we'll enumerate again, but double enumeration over small collection is cheaper than allocation
                this.Activity.TraceId,
                this.Activity.SpanId,
                this.tracerConfiguration);

            if (this.IsRecording)
            {
                this.Activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;

                this.SetLinks(links);
                this.spanProcessor.OnStart(this);
            }
            else
            {
                this.Activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded;
            }

            // this context is definitely not remote, setting isRemote to false
            this.Context = new SpanContext(this.Activity.TraceId, this.Activity.SpanId, this.Activity.ActivityTraceFlags, false, tracestate);
        }
        public void FromDescriptionDefaultTimestampAndAttributes()
        {
            var approxTimestamp = PreciseTimestamp.GetUtcNow();
            var attributes      = new Dictionary <string, object>();

            attributes.Add(
                "MyStringAttributeKey", "MyStringAttributeValue");
            var @event = Event.Create("MyEventText", default, attributes);
        public void FromDescriptionAndDefaultTimestamp()
        {
            var approxTimestamp = PreciseTimestamp.GetUtcNow();
            var @event          = Event.Create("MyEventText", default);

            Assert.Equal("MyEventText", @event.Name);
            Assert.Equal(0, @event.Attributes.Count);
            Assert.InRange(Math.Abs((approxTimestamp - @event.Timestamp).TotalMilliseconds), double.Epsilon, 20);
        }
Exemple #11
0
        public void StartSpanFrom_Recorded_ParentSpan_Kind_Links()
        {
            var tracer = tracerFactory.GetTracer(null);

            var parentSpan  = tracer.StartRootSpan(SpanName);
            var linkContext = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded);

            var startTimestamp = PreciseTimestamp.GetUtcNow();
            var span           = (Span)tracer.StartSpan(SpanName, parentSpan, SpanKind.Server, default, new [] { new Link(linkContext) });
        public void StartSpanWithImplicitTimestamp()
        {
            var timestamp = PreciseTimestamp.GetUtcNow();
            var span      = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
                            .SetSpanKind(SpanKind.Internal)
                            .SetSampler(Samplers.AlwaysSample)
                            .StartSpan();

            Assert.InRange(Math.Abs((timestamp - span.StartTimestamp).TotalMilliseconds), 0, 20);
        }
Exemple #13
0
        // [Fact]
        // public void SettingStateToDisabledWillClearStats_Interval()
        // {
        //    View intervalView =
        //        View.Create(
        //            VIEW_NAME_2,
        //            VIEW_DESCRIPTION,
        //            MeasureDouble,
        //            Mean,
        //            Arrays.asList(Key),
        //            Interval.Create(Duration.Create(60, 0)));
        //    settingStateToDisabledWillClearStats(intervalView);
        // }

        private void SettingStateToDisabledWillClearStats(IView view)
        {
            // TODO: deal with timestamp validation
            var timestamp1 = PreciseTimestamp.GetUtcNow().AddSeconds(-10);

            //clock.Time = timestamp1;
            viewManager.RegisterView(view);
            statsRecorder
            .NewMeasureMap()
            .Put(MeasureDouble, 1.1)
            .Record(tagger.EmptyBuilder.Put(Key, Value).Build());
            TagValues tv = TagValues.Create(new List <string>()
            {
                Value
            });

            StatsTestUtil.AssertAggregationMapEquals(
                viewManager.GetView(view.Name).AggregationMap,
                new Dictionary <TagValues, IAggregationData>()
            {
                { tv, StatsTestUtil.CreateAggregationData(view.Aggregation, view.Measure, 1.1) },
            },
                Epsilon);

            var timestamp2 = timestamp1.AddSeconds(2);

            //clock.Time = timestamp2;
            Stats.State = StatsCollectionState.DISABLED; // This will clear stats.
            Assert.Equal(StatsTestUtil.CreateEmptyViewData(view), viewManager.GetView(view.Name));

            var timestamp3 = timestamp1.AddSeconds(3);

            //clock.Time = timestamp3;
            Stats.State = StatsCollectionState.ENABLED;

            var timestamp4 = timestamp1.AddSeconds(4);
            //clock.Time = timestamp4;
            // This ViewData does not have any stats, but it should not be an empty ViewData, since it has
            // non-zero TimeStamps.
            IViewData viewData = viewManager.GetView(view.Name);

            Assert.Empty(viewData.AggregationMap);
            //Assert.Equal(timestamp3, viewData.Start);
            //Assert.Equal(timestamp4, viewData.End);
            // if (windowData instanceof CumulativeData) {
            //    Assert.Equal(windowData).isEqualTo(CumulativeData.Create(timestamp3, timestamp4));
            // } else {
            //    Assert.Equal(windowData).isEqualTo(IntervalData.Create(timestamp4));
            // }
        }
Exemple #14
0
        public void StartSpanFrom_Recorded_ParentSpan_Kind()
        {
            var tracer = tracerFactory.GetTracer(null);

            var parentSpan = tracer.StartRootSpan(SpanName);

            var startTimestamp = PreciseTimestamp.GetUtcNow();
            var span           = (Span)tracer.StartSpan(SpanName, parentSpan, SpanKind.Client);

            Assert.True(span.IsRecordingEvents);
            Assert.Equal(SpanKind.Client, span.Kind);
            AssertApproxSameTimestamp(startTimestamp, span.StartTimestamp);
            Assert.Empty(span.Links);
        }
Exemple #15
0
        /// <inheritdoc/>
        public ISpan StartRootSpan(string operationName, SpanKind kind, DateTimeOffset startTimestamp, IEnumerable <Link> links)
        {
            if (operationName == null)
            {
                throw new ArgumentNullException(nameof(operationName));
            }

            if (startTimestamp == default)
            {
                startTimestamp = PreciseTimestamp.GetUtcNow();
            }

            return(Span.CreateRoot(operationName, kind, startTimestamp, links, this.tracerConfiguration, this.spanProcessor, this.LibraryResource));
        }
Exemple #16
0
        private Span CreateSampledEndedSpan(string spanName, SpanProcessor spanProcessor)
        {
            var sampledActivity = new Activity(spanName);

            sampledActivity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
            sampledActivity.SetIdFormat(ActivityIdFormat.W3C);
            sampledActivity.Start();
            var span =
                new Span(
                    sampledActivity,
                    Enumerable.Empty <KeyValuePair <string, string> >(),
                    SpanKind.Internal,
                    new TracerConfiguration(),
                    spanProcessor,
                    PreciseTimestamp.GetUtcNow(),
        public void NoEventsRecordedAfterEnd()
        {
            var activityLink = new Activity(SpanName)
                               .SetIdFormat(ActivityIdFormat.W3C)
                               .Start();

            activityLink.Stop();

            var activity = new Activity(SpanName).Start();

            activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;

            var spanStartTime = PreciseTimestamp.GetUtcNow();
            var span          =
                Span.StartSpan(
                    activity,
                    Tracestate.Empty,
                    SpanKind.Internal,
                    TraceParams.Default,
                    startEndHandler);
            var spaEndTime = PreciseTimestamp.GetUtcNow();

            span.End();
            // Check that adding trace events after Span#End() does not throw any exception and are not
            // recorded.
            foreach (var attribute in attributes)
            {
                span.SetAttribute(attribute);
            }

            span.SetAttribute(
                "MySingleStringAttributeKey",
                "MySingleStringAttributeValue");

            span.AddEvent(Event.Create(EventDescription));
            span.AddEvent(EventDescription, attributes);
            span.AddLink(Link.FromActivity(activityLink));
            var spanData = ((Span)span).ToSpanData();

            AssertApproxSameTimestamp(spanData.StartTimestamp, spanStartTime);
            Assert.Empty(spanData.Attributes.AttributeMap);
            Assert.Empty(spanData.Events.Events);
            Assert.Empty(spanData.Links.Links);
            Assert.Equal(Status.Ok, spanData.Status);
            AssertApproxSameTimestamp(spaEndTime, spanData.EndTimestamp);
        }
Exemple #18
0
        public void StartSpanFrom_Recorded_ParentSpan_Kind_Links_Enumerable()
        {
            var tracer = tracerFactory.GetTracer(null);

            var parentSpan  = tracer.StartRootSpan(SpanName);
            var linkContext = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded);

            var startTimestamp = PreciseTimestamp.GetUtcNow();
            var span           = (Span)tracer.StartSpan(SpanName, parentSpan, SpanKind.Server, new SpanCreationOptions {
                Links = new[] { new Link(linkContext) }
            });

            Assert.True(span.IsRecording);
            Assert.Equal(SpanKind.Server, span.Kind);
            AssertApproxSameTimestamp(startTimestamp, span.StartTimestamp);
            Assert.Single(span.Links);
            Assert.Same(linkContext, span.Links.Single().Context);
        }
Exemple #19
0
        private Span CreateNotSampledEndedSpan(string spanName)
        {
            var notSampledActivity = new Activity(spanName);

            notSampledActivity.SetIdFormat(ActivityIdFormat.W3C);
            notSampledActivity.Start();
            var span =
                new Span(
                    notSampledActivity,
                    Tracestate.Empty,
                    SpanKind.Internal,
                    TraceConfig.Default,
                    spanProcessor,
                    PreciseTimestamp.GetUtcNow(),
                    false);

            span.End();
            return(span);
        }
Exemple #20
0
        private Span CreateSampledEndedSpan(string spanName)
        {
            var sampledActivity = new Activity(spanName);

            sampledActivity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
            sampledActivity.SetIdFormat(ActivityIdFormat.W3C);
            sampledActivity.Start();
            var span =
                new Span(
                    sampledActivity,
                    Tracestate.Empty,
                    SpanKind.Internal,
                    TraceConfig.Default,
                    spanProcessor,
                    PreciseTimestamp.GetUtcNow(),
                    default);

            span.End();
            return(span);
        }
Exemple #21
0
        public void StartSpanFrom_NotRecorded_ParentSpan()
        {
            var tracer = tracerFactory.GetTracer(null);

            var grandParentContext = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None);
            var parentSpan         = (Span)tracer.StartSpan(SpanName, grandParentContext);

            var startTimestamp = PreciseTimestamp.GetUtcNow();
            var span           = (Span)tracer.StartSpan(SpanName, parentSpan);

            Assert.True(span.Context.IsValid);
            Assert.Equal(parentSpan.Context.TraceId, span.Context.TraceId);
            Assert.Equal(span.Activity.SpanId, span.Context.SpanId);
            Assert.Equal(parentSpan.Context.SpanId, span.ParentSpanId);
            Assert.Equal(parentSpan.Context.TraceOptions, span.Context.TraceOptions);
            Assert.Empty(span.Context.Tracestate);

            Assert.False(span.IsRecordingEvents);
            Assert.Equal(SpanKind.Internal, span.Kind);
            AssertApproxSameTimestamp(startTimestamp, span.StartTimestamp);
            Assert.Empty(span.Links);
        }
        public void StartSpanNullParent()
        {
            var span = new SpanBuilder(SpanName, spanBuilderOptions)
                       .SetSpanKind(SpanKind.Internal)
                       .SetNoParent()
                       .StartSpan();

            Assert.True(span.Context.IsValid);
            Assert.True(span.IsRecordingEvents);
            Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
            var spanData = ((Span)span).ToSpanData();

            Assert.True(spanData.ParentSpanId == default);
            Assert.InRange(spanData.StartTimestamp, PreciseTimestamp.GetUtcNow().AddSeconds(-1), PreciseTimestamp.GetUtcNow().AddSeconds(1));
            Assert.Equal(SpanName, spanData.Name);

            var activity = ((Span)span).Activity;

            Assert.Null(Activity.Current);
            Assert.Equal(activity.TraceId, span.Context.TraceId);
            Assert.Equal(activity.SpanId, span.Context.SpanId);
        }
        public void ThrowsInExporter()
        {
            spanExporter  = new TestExporter(_ => throw new ArgumentException("123"));
            spanProcessor = new SimpleSpanProcessor(spanExporter);

            var sampledActivity = new Activity("foo");

            sampledActivity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
            sampledActivity.SetIdFormat(ActivityIdFormat.W3C);
            sampledActivity.Start();
            var span =
                new Span(
                    sampledActivity,
                    Tracestate.Empty,
                    SpanKind.Internal,
                    TraceConfig.Default,
                    spanProcessor,
                    PreciseTimestamp.GetUtcNow(),
                    default);

            // does not throw
            span.End();
        }
Exemple #24
0
        /// <inheritdoc/>
        public void AddEvent(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (!this.IsRecordingEvents || this.hasEnded)
            {
                return;
            }

            lock (this.@lock)
            {
                if (this.events == null)
                {
                    this.events =
                        new EvictingQueue <Event>(this.tracerConfiguration.MaxNumberOfEvents);
                }

                this.events.AddEvent(new Event(name, PreciseTimestamp.GetUtcNow()));
            }
        }
        /// <inheritdoc/>
        public void AddEvent(IEvent addEvent)
        {
            if (addEvent == null)
            {
                throw new ArgumentNullException(nameof(addEvent));
            }

            if (!this.IsRecordingEvents)
            {
                return;
            }

            lock (this.@lock)
            {
                if (this.HasEnded)
                {
                    // logger.log(Level.FINE, "Calling AddEvent() on an ended Span.");
                    return;
                }

                this.InitializedEvents.AddEvent(TimedEvent <IEvent> .Create(PreciseTimestamp.GetUtcNow(), addEvent));
            }
        }
Exemple #26
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Event"/> class.
 /// </summary>
 /// <param name="name">Event name.</param>
 public Event(string name)
     : this(name, PreciseTimestamp.GetUtcNow(), EmptyAttributes)
 {
 }
Exemple #27
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Event"/> class.
 /// </summary>
 /// <param name="name">Event name.</param>
 /// <param name="timestamp">Event timestamp. Timestamp MUST only be used for the events that happened in the past, not at the moment of this call.</param>
 /// <param name="attributes">Event attributes.</param>
 public Event(string name, DateTimeOffset timestamp, IDictionary <string, object> attributes)
 {
     this.Name       = name ?? throw new ArgumentNullException(nameof(name));
     this.Attributes = attributes ?? throw new ArgumentNullException(nameof(attributes));
     this.Timestamp  = timestamp != default ? timestamp : PreciseTimestamp.GetUtcNow();
 }
Exemple #28
0
 /// <inheritdoc/>
 public void End()
 {
     this.End(PreciseTimestamp.GetUtcNow());
 }
Exemple #29
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Event"/> class.
 /// </summary>
 /// <param name="name">Event name.</param>
 /// <param name="timestamp">Event timestamp. Timestamp MUST only be used for the events that happened in the past, not at the moment of this call.</param>
 /// <param name="attributes">Event attributes.</param>
 public Event(string name, DateTimeOffset timestamp, IDictionary <string, object> attributes)
 {
     this.Name       = name ?? string.Empty;
     this.Attributes = attributes ?? EmptyAttributes;
     this.Timestamp  = timestamp != default ? timestamp : PreciseTimestamp.GetUtcNow();
 }
Exemple #30
0
        private Span(
            string name,
            SpanContext parentSpanContext,
            ActivityAndTracestate activityAndTracestate,
            bool createdFromActivity,
            SpanKind spanKind,
            SpanCreationOptions spanCreationOptions,
            Sampler sampler,
            TracerConfiguration tracerConfiguration,
            SpanProcessor spanProcessor,
            Resource libraryResource)
        {
            if (name != null)
            {
                this.Name = name;
            }
            else
            {
                OpenTelemetrySdkEventSource.Log.InvalidArgument("StartSpan", "span name is null");
                this.Name = string.Empty;
            }

            this.LibraryResource = libraryResource;

            IEnumerable <Link> links = null;

            if (spanCreationOptions != null)
            {
                links = spanCreationOptions.Links ?? spanCreationOptions.LinksFactory?.Invoke();
                this.startTimestamp = spanCreationOptions.StartTimestamp;
            }

            if (this.startTimestamp == default)
            {
                this.startTimestamp = PreciseTimestamp.GetUtcNow();
            }

            this.sampler             = sampler;
            this.tracerConfiguration = tracerConfiguration;
            this.spanProcessor       = spanProcessor;
            this.Kind = spanKind;
            this.createdFromActivity = createdFromActivity;
            this.Activity            = activityAndTracestate.Activity;
            var tracestate = activityAndTracestate.Tracestate;

            this.IsRecording = MakeSamplingDecision(
                parentSpanContext,
                name,
                spanCreationOptions?.Attributes,
                links, // we'll enumerate again, but double enumeration over small collection is cheaper than allocation
                this.Activity.TraceId,
                this.Activity.SpanId,
                this.sampler);

            this.Activity.ActivityTraceFlags =
                this.IsRecording
                ? this.Activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded
                : this.Activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded;

            // this context is definitely not remote, setting isRemote to false
            this.Context = new SpanContext(this.Activity.TraceId, this.Activity.SpanId, this.Activity.ActivityTraceFlags, false, tracestate);

            if (this.IsRecording)
            {
                this.SetLinks(links);

                if (spanCreationOptions?.Attributes != null)
                {
                    foreach (var attribute in spanCreationOptions.Attributes)
                    {
                        this.SetAttribute(attribute);
                    }
                }

                this.spanProcessor.OnStart(this);
            }
        }