File: System\Diagnostics\ActivityCreationOptions.cs
Web Access
Project: src\src\libraries\System.Diagnostics.DiagnosticSource\src\System.Diagnostics.DiagnosticSource.csproj (System.Diagnostics.DiagnosticSource)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Runtime.CompilerServices;
 
namespace System.Diagnostics
{
    /// <summary>
    /// ActivityCreationOptions is encapsulating all needed information which will be sent to the ActivityListener to decide about creating the Activity object and with what state.
    /// The possible generic type parameters is <see cref="ActivityContext"/> or <see cref="string"/>
    /// </summary>
    public readonly struct ActivityCreationOptions<T>
    {
        private readonly ActivityTagsCollection? _samplerTags;
        private readonly ActivityContext _context;
        private readonly string? _traceState;
 
        /// <summary>
        /// Construct a new <see cref="ActivityCreationOptions{T}"/> object.
        /// </summary>
        /// <param name="source">The trace Activity source<see cref="ActivitySource"/> used to request creating the Activity object.</param>
        /// <param name="name">The operation name of the Activity.</param>
        /// <param name="parent">The requested parent to create the Activity object with. The parent either be a parent Id represented as string or it can be a parent context <see cref="ActivityContext"/>.</param>
        /// <param name="kind"><see cref="ActivityKind"/> to create the Activity object with.</param>
        /// <param name="tags">Key-value pairs list for the tags to create the Activity object with.<see cref="ActivityContext"/></param>
        /// <param name="links"><see cref="ActivityLink"/> list to create the Activity object with.</param>
        /// <param name="idFormat">The default Id format to use.</param>
        internal ActivityCreationOptions(ActivitySource source, string name, T parent, ActivityKind kind, IEnumerable<KeyValuePair<string, object?>>? tags, IEnumerable<ActivityLink>? links, ActivityIdFormat idFormat)
        {
            Source = source;
            Name = name;
            Kind = kind;
            Parent = parent;
            Tags = tags;
            Links = links;
            IdFormat = idFormat;
 
            if (IdFormat == ActivityIdFormat.Unknown && Activity.ForceDefaultIdFormat)
            {
                IdFormat = Activity.DefaultIdFormat;
            }
 
            _samplerTags = null;
            _traceState = null;
 
            if (parent is ActivityContext ac && ac != default)
            {
                _context = ac;
                if (IdFormat == ActivityIdFormat.Unknown)
                {
                    IdFormat = ActivityIdFormat.W3C;
                }
 
                _traceState = ac.TraceState;
            }
            else if (parent is string p)
            {
                if (IdFormat != ActivityIdFormat.Hierarchical)
                {
                    if (ActivityContext.TryParse(p, null, out _context))
                    {
                        IdFormat = ActivityIdFormat.W3C;
                    }
 
                    if (IdFormat == ActivityIdFormat.Unknown)
                    {
                        IdFormat = ActivityIdFormat.Hierarchical;
                    }
                }
                else
                {
                    _context = default;
                }
            }
            else
            {
                _context = default;
                if (IdFormat == ActivityIdFormat.Unknown)
                {
                    IdFormat = Activity.Current != null ? Activity.Current.IdFormat : Activity.DefaultIdFormat;
                }
            }
        }
 
        /// <summary>
        /// Retrieve the <see cref="ActivitySource"/> object.
        /// </summary>
        public ActivitySource Source { get; }
 
        /// <summary>
        /// Retrieve the name which requested to create the Activity object with.
        /// </summary>
        public string Name { get; }
 
        /// <summary>
        /// Retrieve the <see cref="ActivityKind"/> which requested to create the Activity object with.
        /// </summary>
        public ActivityKind Kind { get; }
 
        /// <summary>
        /// Retrieve the parent which requested to create the Activity object with. Parent will be either in form of string or <see cref="ActivityContext"/>.
        /// </summary>
        public T Parent { get; }
 
        /// <summary>
        /// Retrieve the tags which requested to create the Activity object with.
        /// </summary>
        public IEnumerable<KeyValuePair<string, object?>>? Tags { get; }
 
        /// <summary>
        /// Retrieve the list of <see cref="ActivityLink"/> which requested to create the Activity object with.
        /// </summary>
        public IEnumerable<ActivityLink>? Links { get; }
 
        public ActivityTagsCollection SamplingTags
        {
            get
            {
                if (_samplerTags == null)
                {
                    // Because the struct is readonly, we cannot directly assign _samplerTags. We have to workaround it by calling Unsafe.AsRef
                    Unsafe.AsRef(in _samplerTags) = new ActivityTagsCollection();
                }
 
                return _samplerTags!;
            }
        }
 
        public ActivityTraceId TraceId
        {
            get
            {
                if (Parent is ActivityContext && IdFormat == ActivityIdFormat.W3C && _context == default)
                {
                    Func<ActivityTraceId>? traceIdGenerator = Activity.TraceIdGenerator;
                    ActivityTraceId id = traceIdGenerator == null ? ActivityTraceId.CreateRandom() : traceIdGenerator();
 
                    // Because the struct is readonly, we cannot directly assign _context. We have to workaround it by calling Unsafe.AsRef
                    Unsafe.AsRef(in _context) = new ActivityContext(id, default, ActivityTraceFlags.None);
                }
 
                return _context.TraceId;
            }
        }
 
        /// <summary>
        /// Retrieve or initialize the trace state to use for the Activity we may create.
        /// </summary>
        public string? TraceState
        {
            get => _traceState;
            init
            {
                _traceState = value;
            }
        }
 
        // SetTraceState is to set the _traceState without the need of copying the whole structure.
        internal void SetTraceState(string? traceState) => Unsafe.AsRef(in _traceState) = traceState;
 
        /// <summary>
        /// Retrieve Id format of to use for the Activity we may create.
        /// </summary>
        internal ActivityIdFormat IdFormat { get; }
 
        // Helper to access the sampling tags. The SamplingTags Getter can allocate when not necessary.
        internal ActivityTagsCollection? GetSamplingTags() => _samplerTags;
 
        internal ActivityContext GetContext() => _context;
    }
}