internal static ZipkinSpan ToZipkinSpan(this SpanData otelSpan, ZipkinEndpoint defaultLocalEndpoint, bool useShortTraceIds = false)
        {
            var context        = otelSpan.Context;
            var startTimestamp = ToEpochMicroseconds(otelSpan.StartTimestamp);
            var endTimestamp   = ToEpochMicroseconds(otelSpan.EndTimestamp);

            string parentId = null;

            if (otelSpan.ParentSpanId != default)
            {
                parentId = EncodeSpanId(otelSpan.ParentSpanId);
            }

            var attributeEnumerationState = new AttributeEnumerationState
            {
                Tags = PooledList <KeyValuePair <string, string> > .Create(),
            };

            DictionaryEnumerator <string, object, AttributeEnumerationState> .AllocationFreeForEach(otelSpan.Attributes, ref attributeEnumerationState, ProcessAttributesRef);

            DictionaryEnumerator <string, object, AttributeEnumerationState> .AllocationFreeForEach(otelSpan.LibraryResource.Attributes, ref attributeEnumerationState, ProcessLibraryResourcesRef);

            var localEndpoint = defaultLocalEndpoint;

            var serviceName = attributeEnumerationState.ServiceName;

            // override default service name
            if (!string.IsNullOrWhiteSpace(serviceName))
            {
                if (!string.IsNullOrWhiteSpace(attributeEnumerationState.ServiceNamespace))
                {
                    serviceName = attributeEnumerationState.ServiceNamespace + "." + serviceName;
                }

                if (!LocalEndpointCache.TryGetValue(serviceName, out localEndpoint))
                {
                    localEndpoint = defaultLocalEndpoint.Clone(serviceName);
                    LocalEndpointCache.TryAdd(serviceName, localEndpoint);
                }
            }

            ZipkinEndpoint remoteEndpoint = null;

            if ((otelSpan.Kind == SpanKind.Client || otelSpan.Kind == SpanKind.Producer) && attributeEnumerationState.RemoteEndpointServiceName != null)
            {
                remoteEndpoint = RemoteEndpointCache.GetOrAdd(attributeEnumerationState.RemoteEndpointServiceName, ZipkinEndpoint.Create);
            }

            var status = otelSpan.Status;

            if (status.IsValid)
            {
                if (!CanonicalCodeCache.TryGetValue(status.CanonicalCode, out string canonicalCode))
                {
                    canonicalCode = status.CanonicalCode.ToString();
                    CanonicalCodeCache.TryAdd(status.CanonicalCode, canonicalCode);
                }

                PooledList <KeyValuePair <string, string> > .Add(ref attributeEnumerationState.Tags, new KeyValuePair <string, string>(StatusCode, canonicalCode));

                if (status.Description != null)
                {
                    PooledList <KeyValuePair <string, string> > .Add(ref attributeEnumerationState.Tags, new KeyValuePair <string, string>(StatusDescription, status.Description));
                }
            }

            var annotations = PooledList <ZipkinAnnotation> .Create();

            ListEnumerator <Event, PooledList <ZipkinAnnotation> > .AllocationFreeForEach(otelSpan.Events, ref annotations, ProcessEventsRef);

            return(new ZipkinSpan(
                       EncodeTraceId(context.TraceId, useShortTraceIds),
                       parentId,
                       EncodeSpanId(context.SpanId),
                       ToSpanKind(otelSpan),
                       otelSpan.Name,
                       ToEpochMicroseconds(otelSpan.StartTimestamp),
                       duration: endTimestamp - startTimestamp,
                       localEndpoint,
                       remoteEndpoint,
                       annotations,
                       attributeEnumerationState.Tags,
                       null,
                       null));
        }
        internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint defaultLocalEndpoint, bool useShortTraceIds = false)
        {
            var context        = activity.Context;
            var startTimestamp = activity.StartTimeUtc.ToEpochMicroseconds();

            string parentId = EncodeSpanId(activity.ParentSpanId);

            if (string.Equals(parentId, InvalidSpanId, StringComparison.Ordinal))
            {
                parentId = null;
            }

            var attributeEnumerationState = new AttributeEnumerationState
            {
                Tags = PooledList <KeyValuePair <string, string> > .Create(),
            };

            DictionaryEnumerator <string, string, AttributeEnumerationState> .AllocationFreeForEach(activity.Tags, ref attributeEnumerationState, ProcessTagsRef);

            var activitySource = activity.Source;

            if (!string.IsNullOrEmpty(activitySource.Name))
            {
                PooledList <KeyValuePair <string, string> > .Add(ref attributeEnumerationState.Tags, new KeyValuePair <string, string>("library.name", activitySource.Name));

                if (!string.IsNullOrEmpty(activitySource.Version))
                {
                    PooledList <KeyValuePair <string, string> > .Add(ref attributeEnumerationState.Tags, new KeyValuePair <string, string>("library.version", activitySource.Version));
                }
            }

            var localEndpoint = defaultLocalEndpoint;

            var serviceName = attributeEnumerationState.ServiceName;

            // override default service name
            if (!string.IsNullOrWhiteSpace(serviceName))
            {
                if (!string.IsNullOrWhiteSpace(attributeEnumerationState.ServiceNamespace))
                {
                    serviceName = attributeEnumerationState.ServiceNamespace + "." + serviceName;
                }

                if (!LocalEndpointCache.TryGetValue(serviceName, out localEndpoint))
                {
                    localEndpoint = defaultLocalEndpoint.Clone(serviceName);
                    LocalEndpointCache.TryAdd(serviceName, localEndpoint);
                }
            }

            ZipkinEndpoint remoteEndpoint = null;

            if ((activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer) && attributeEnumerationState.RemoteEndpointServiceName != null)
            {
                remoteEndpoint = RemoteEndpointCache.GetOrAdd(attributeEnumerationState.RemoteEndpointServiceName, ZipkinEndpoint.Create);
            }

            var annotations = PooledList <ZipkinAnnotation> .Create();

            ListEnumerator <ActivityEvent, PooledList <ZipkinAnnotation> > .AllocationFreeForEach(activity.Events, ref annotations, ProcessActivityEventsRef);

            return(new ZipkinSpan(
                       EncodeTraceId(context.TraceId, useShortTraceIds),
                       parentId,
                       EncodeSpanId(context.SpanId),
                       ToActivityKind(activity),
                       activity.OperationName,
                       activity.StartTimeUtc.ToEpochMicroseconds(),
                       duration: (long)activity.Duration.ToEpochMicroseconds(),
                       localEndpoint,
                       remoteEndpoint,
                       annotations,
                       attributeEnumerationState.Tags,
                       null,
                       null));
        }