public ActivitySource(string name, string?version = "")
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            Name    = name;
            Version = version;

            s_activeSources.Add(this);

            if (s_allListeners.Count > 0)
            {
                s_allListeners.EnumWithAction((listener, source) =>
                {
                    Func <ActivitySource, bool>?shouldListenTo = listener.ShouldListenTo;
                    if (shouldListenTo != null)
                    {
                        var activitySource = (ActivitySource)source;
                        if (shouldListenTo(activitySource))
                        {
                            activitySource.AddListener(listener);
                        }
                    }
                }, this);
            }

            GC.KeepAlive(DiagnosticSourceEventSource.Logger);
        }
        public static void AddActivityListener(ActivityListener listener)
        {
            if (listener == null)
            {
                throw new ArgumentNullException(nameof(listener));
            }

            if (s_allListeners.AddIfNotExist(listener))
            {
                s_activeSources.EnumWithAction((source, obj) => {
                    var shouldListenTo = ((ActivityListener)obj).ShouldListenTo;
                    if (shouldListenTo != null && shouldListenTo(source))
                    {
                        source.AddListener((ActivityListener)obj);
                    }
                }, listener);
            }
        }
        internal void NotifyActivityStop(Activity activity)
        {
            Debug.Assert(activity != null);

            // _listeners can get assigned to null in Dispose.
            SynchronizedList <ActivityListener>?listeners = _listeners;

            if (listeners != null && listeners.Count > 0)
            {
                listeners.EnumWithAction((listener, obj) => listener.ActivityStopped?.Invoke((Activity)obj), activity);
            }
        }
        private Activity?StartActivity(string name, ActivityKind kind, ActivityContext context, string?parentId, IEnumerable <KeyValuePair <string, object?> >?tags, IEnumerable <ActivityLink>?links, DateTimeOffset startTime)
        {
            // _listeners can get assigned to null in Dispose.
            SynchronizedList <ActivityListener>?listeners = _listeners;

            if (listeners == null || listeners.Count == 0)
            {
                return(null);
            }

            Activity?activity = null;
            ActivityTagsCollection?samplerTags;

            ActivitySamplingResult samplingResult = ActivitySamplingResult.None;

            if (parentId != null)
            {
                var aco        = new ActivityCreationOptions <string>(this, name, parentId, kind, tags, links);
                var acoContext = new ActivityCreationOptions <ActivityContext>(this, name, aco.GetContext(), kind, tags, links);

                listeners.EnumWithFunc((ActivityListener listener, ref ActivityCreationOptions <string> data, ref ActivitySamplingResult result, ref ActivityCreationOptions <ActivityContext> dataWithContext) => {
                    SampleActivity <string>?sampleUsingParentId = listener.SampleUsingParentId;
                    if (sampleUsingParentId != null)
                    {
                        ActivitySamplingResult sr = sampleUsingParentId(ref data);
                        if (sr > result)
                        {
                            result = sr;
                        }
                    }
                    else
                    {
                        // In case we have a parent Id and the listener not providing the SampleUsingParentId, we'll try to find out if the following conditions are true:
                        //   - The listener is providing the Sample callback
                        //   - Can convert the parent Id to a Context. ActivityCreationOptions.TraceId != default means parent id converted to a valid context.
                        // Then we can call the listener Sample callback with the constructed context.
                        SampleActivity <ActivityContext>?sample = listener.Sample;
                        if (sample != null && data.GetContext() != default) // data.GetContext() != default means parent Id parsed correctly to a context
                        {
                            ActivitySamplingResult sr = sample(ref dataWithContext);
                            if (sr > result)
                            {
                                result = sr;
                            }
                        }
                    }
                }, ref aco, ref samplingResult, ref acoContext);

                if (context == default && aco.GetContext() != default)
                {
                    context  = aco.GetContext();
                    parentId = null;
                }

                samplerTags = aco.GetSamplingTags();
                ActivityTagsCollection?atc = acoContext.GetSamplingTags();
                if (atc != null)
                {
                    if (samplerTags == null)
                    {
                        samplerTags = atc;
                    }
                    else
                    {
                        foreach (KeyValuePair <string, object?> tag in atc)
                        {
                            samplerTags.Add(tag);
                        }
                    }
                }
            }
            else
            {
                bool useCurrentActivityContext = context == default && Activity.Current != null;
                var  aco = new ActivityCreationOptions <ActivityContext>(this, name, useCurrentActivityContext ? Activity.Current !.Context : context, kind, tags, links);
                listeners.EnumWithFunc((ActivityListener listener, ref ActivityCreationOptions <ActivityContext> data, ref ActivitySamplingResult result, ref ActivityCreationOptions <ActivityContext> unused) => {
                    SampleActivity <ActivityContext>?sample = listener.Sample;
                    if (sample != null)
                    {
                        ActivitySamplingResult dr = sample(ref data);
                        if (dr > result)
                        {
                            result = dr;
                        }
                    }
                }, ref aco, ref samplingResult, ref aco);

                if (!useCurrentActivityContext)
                {
                    // We use the context stored inside ActivityCreationOptions as it is possible the trace id get automatically generated during the sampling.
                    // We don't use the context stored inside ActivityCreationOptions only in case if we used Activity.Current context, the reason is we need to
                    // create the new child activity with Parent set to Activity.Current.
                    context = aco.GetContext();
                }

                samplerTags = aco.GetSamplingTags();
            }

            if (samplingResult != ActivitySamplingResult.None)
            {
                activity = Activity.CreateAndStart(this, name, kind, parentId, context, tags, links, startTime, samplerTags, samplingResult);
                listeners.EnumWithAction((listener, obj) => listener.ActivityStarted?.Invoke((Activity)obj), activity);
            }

            return(activity);
        }