public Batch(Process process)
        {
            Guard.Null(process, nameof(process));

            this.Process      = process;
            this.spanMessages = PooledList <BufferWriterMemory> .Create();
        }
        private static bool ProcessActivityEvent(ref PooledListState <JaegerLog> state, ActivityEvent e)
        {
            if (!state.Created)
            {
                state.List = PooledList <JaegerLog> .Create();

                state.Created = true;
            }

            PooledList <JaegerLog> .Add(ref state.List, e.ToJaegerLog());

            return(true);
        }
        private static bool ProcessActivityLink(ref PooledListState <JaegerSpanRef> state, ActivityLink link)
        {
            if (!state.Created)
            {
                state.List = PooledList <JaegerSpanRef> .Create();

                state.Created = true;
            }

            PooledList <JaegerSpanRef> .Add(ref state.List, link.ToJaegerSpanRef());

            return(true);
        }
        public static JaegerLog ToJaegerLog(this Event timedEvent)
        {
            var tags = PooledList <JaegerTag> .Create();

            foreach (var attribute in timedEvent.Attributes)
            {
                PooledList <JaegerTag> .Add(ref tags, attribute.ToJaegerTag());
            }

            // Matches what OpenTracing and OpenTelemetry defines as the event name.
            // https://github.com/opentracing/specification/blob/master/semantic_conventions.md#log-fields-table
            // https://github.com/open-telemetry/opentelemetry-specification/pull/397/files
            PooledList <JaegerTag> .Add(ref tags, new JaegerTag("message", JaegerTagType.STRING, vStr : timedEvent.Name));

            return(new JaegerLog(timedEvent.Timestamp.ToEpochMicroseconds(), tags));
        }
        public static JaegerLog ToJaegerLog(this ActivityEvent timedEvent)
        {
            var jaegerTags = new EventTagsEnumerationState
            {
                Tags = PooledList <JaegerTag> .Create(),
            };

            timedEvent.EnumerateTags(ref jaegerTags);

            // Matches what OpenTracing and OpenTelemetry defines as the event name.
            // https://github.com/opentracing/specification/blob/master/semantic_conventions.md#log-fields-table
            // https://github.com/open-telemetry/opentelemetry-specification/pull/397/files
            PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("message", JaegerTagType.STRING, vStr : timedEvent.Name));

            // TODO: Use the same function as JaegerConversionExtensions or check that the perf here is acceptable.
            return(new JaegerLog(timedEvent.Timestamp.ToEpochMicroseconds(), jaegerTags.Tags));
        }
Exemple #6
0
        public static JaegerLog ToJaegerLog(this ActivityEvent timedEvent)
        {
            var jaegerTags = new EventTagsEnumerationState
            {
                Tags = PooledList <JaegerTag> .Create(),
            };

            timedEvent.EnumerateTags(ref jaegerTags);

            if (!jaegerTags.HasEvent)
            {
                // https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk_exporters/jaeger.md#events
                PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("event", JaegerTagType.STRING, vStr : timedEvent.Name));
            }

            // TODO: Use the same function as JaegerConversionExtensions or check that the perf here is acceptable.
            return(new JaegerLog(timedEvent.Timestamp.ToEpochMicroseconds(), jaegerTags.Tags));
        }
        public static PooledList <JaegerSpanRef> ToJaegerSpanRefs(this IEnumerable <Link> links)
        {
            bool created = false;
            PooledList <JaegerSpanRef> references = default;

            foreach (var link in links ?? Array.Empty <Link>())
            {
                if (!created)
                {
                    references = PooledList <JaegerSpanRef> .Create();

                    created = true;
                }

                PooledList <JaegerSpanRef> .Add(ref references, link.ToJaegerSpanRef());
            }

            return(references);
        }
        public static JaegerLog ToJaegerLog(this Event timedEvent)
        {
            var tags = new PooledListState <JaegerTag>
            {
                Created = true,
                List    = PooledList <JaegerTag> .Create(),
            };

            DictionaryEnumerator <string, object, PooledListState <JaegerTag> > .AllocationFreeForEach(
                timedEvent.Attributes,
                ref tags,
                ProcessTagRef);

            // Matches what OpenTracing and OpenTelemetry defines as the event name.
            // https://github.com/opentracing/specification/blob/master/semantic_conventions.md#log-fields-table
            // https://github.com/open-telemetry/opentelemetry-specification/pull/397/files
            PooledList <JaegerTag> .Add(ref tags.List, new JaegerTag("message", JaegerTagType.STRING, vStr : timedEvent.Name));

            return(new JaegerLog(timedEvent.Timestamp.ToEpochMicroseconds(), tags.List));
        }
        public static PooledList <JaegerLog> ToJaegerLogs(this IEnumerable <Event> events)
        {
            bool created = false;
            PooledList <JaegerLog> logs = default;

            foreach (var e in events ?? Array.Empty <Event>())
            {
                if (e == null)
                {
                    continue;
                }

                if (!created)
                {
                    logs = PooledList <JaegerLog> .Create();

                    created = true;
                }

                PooledList <JaegerLog> .Add(ref logs, e.ToJaegerLog());
            }

            return(logs);
        }
Exemple #10
0
 public Batch(Process process)
 {
     this.Process      = process ?? throw new ArgumentNullException(nameof(process));
     this.spanMessages = PooledList <BufferWriterMemory> .Create();
 }
        public static JaegerSpan ToJaegerSpan(this Activity activity)
        {
            var jaegerTags = new TagState
            {
                Tags = PooledList <JaegerTag> .Create(),
            };

            DictionaryEnumerator <string, string, TagState> .AllocationFreeForEach(
                activity.Tags,
                ref jaegerTags,
                ProcessActivityTagRef);

            string peerServiceName = null;

            if ((activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer) && jaegerTags.PeerService != null)
            {
                // Send peer.service for remote calls.
                peerServiceName = jaegerTags.PeerService;

                // If priority = 0 that means peer.service was already included in tags.
                if (jaegerTags.PeerServicePriority > 0)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag(SpanAttributeConstants.PeerServiceKey, JaegerTagType.STRING, vStr : peerServiceName));
                }
            }

            // The Span.Kind must translate into a tag.
            // See https://opentracing.io/specification/conventions/
            if (activity.Kind != ActivityKind.Internal)
            {
                string spanKind = null;

                if (activity.Kind == ActivityKind.Server)
                {
                    spanKind = "server";
                }
                else if (activity.Kind == ActivityKind.Client)
                {
                    spanKind = "client";
                }
                else if (activity.Kind == ActivityKind.Consumer)
                {
                    spanKind = "consumer";
                }
                else if (activity.Kind == ActivityKind.Producer)
                {
                    spanKind = "producer";
                }

                if (spanKind != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("span.kind", JaegerTagType.STRING, vStr : spanKind));
                }
            }

            var activitySource = activity.Source;

            if (!string.IsNullOrEmpty(activitySource.Name))
            {
                PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("library.name", JaegerTagType.STRING, vStr : activitySource.Name));

                if (!string.IsNullOrEmpty(activitySource.Version))
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("library.version", JaegerTagType.STRING, vStr : activitySource.Version));
                }
            }

            var traceId      = Int128.Empty;
            var spanId       = Int128.Empty;
            var parentSpanId = Int128.Empty;

            if (activity.IdFormat == ActivityIdFormat.W3C)
            {
                // TODO: The check above should be enforced by the usage of the exporter. Perhaps enforce at higher-level.
                traceId      = new Int128(activity.TraceId);
                spanId       = new Int128(activity.SpanId);
                parentSpanId = new Int128(activity.ParentSpanId);
            }

            return(new JaegerSpan(
                       peerServiceName: peerServiceName,
                       traceIdLow: traceId.Low,
                       traceIdHigh: traceId.High,
                       spanId: spanId.Low,
                       parentSpanId: parentSpanId.Low,
                       operationName: activity.DisplayName,
                       flags: (activity.Context.TraceFlags & ActivityTraceFlags.Recorded) > 0 ? 0x1 : 0,
                       startTime: ToEpochMicroseconds(activity.StartTimeUtc),
                       duration: (long)activity.Duration.TotalMilliseconds * 1000,
                       references: activity.Links.ToJaegerSpanRefs(),
                       tags: jaegerTags.Tags,
                       logs: activity.Events.ToJaegerLogs()));
        }
        public static JaegerSpan ToJaegerSpan(this Activity activity)
        {
            var jaegerTags = new TagEnumerationState
            {
                Tags = PooledList <JaegerTag> .Create(),
            };

            activity.EnumerateTags(ref jaegerTags);

            string peerServiceName = null;

            if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer)
            {
                // If priority = 0 that means peer.service may have already been included in tags
                var addPeerServiceTag = jaegerTags.PeerServicePriority > 0;

                var hostNameOrIpAddress = jaegerTags.HostName ?? jaegerTags.IpAddress;

                // peer.service has not already been included, but net.peer.name/ip and optionally net.peer.port are present
                if ((jaegerTags.PeerService == null || addPeerServiceTag) &&
                    hostNameOrIpAddress != null)
                {
                    peerServiceName = jaegerTags.Port == default
                        ? hostNameOrIpAddress
                        : $"{hostNameOrIpAddress}:{jaegerTags.Port}";

                    // Add the peer.service tag
                    addPeerServiceTag = true;
                }

                if (peerServiceName == null && jaegerTags.PeerService != null)
                {
                    peerServiceName = jaegerTags.PeerService;
                }

                if (peerServiceName != null && addPeerServiceTag)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag(SemanticConventions.AttributePeerService, JaegerTagType.STRING, vStr : peerServiceName));
                }
            }

            // The Span.Kind must translate into a tag.
            // See https://opentracing.io/specification/conventions/
            if (activity.Kind != ActivityKind.Internal)
            {
                string spanKind = null;

                if (activity.Kind == ActivityKind.Server)
                {
                    spanKind = "server";
                }
                else if (activity.Kind == ActivityKind.Client)
                {
                    spanKind = "client";
                }
                else if (activity.Kind == ActivityKind.Consumer)
                {
                    spanKind = "consumer";
                }
                else if (activity.Kind == ActivityKind.Producer)
                {
                    spanKind = "producer";
                }

                if (spanKind != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("span.kind", JaegerTagType.STRING, vStr : spanKind));
                }
            }

            var activitySource = activity.Source;

            if (!string.IsNullOrEmpty(activitySource.Name))
            {
                PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("library.name", JaegerTagType.STRING, vStr : activitySource.Name));

                if (!string.IsNullOrEmpty(activitySource.Version))
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("library.version", JaegerTagType.STRING, vStr : activitySource.Version));
                }
            }

            var traceId      = Int128.Empty;
            var spanId       = Int128.Empty;
            var parentSpanId = Int128.Empty;

            if (activity.IdFormat == ActivityIdFormat.W3C)
            {
                // TODO: The check above should be enforced by the usage of the exporter. Perhaps enforce at higher-level.
                traceId      = new Int128(activity.TraceId);
                spanId       = new Int128(activity.SpanId);
                parentSpanId = new Int128(activity.ParentSpanId);
            }

            return(new JaegerSpan(
                       peerServiceName: peerServiceName,
                       traceIdLow: traceId.Low,
                       traceIdHigh: traceId.High,
                       spanId: spanId.Low,
                       parentSpanId: parentSpanId.Low,
                       operationName: activity.DisplayName,
                       flags: (activity.Context.TraceFlags & ActivityTraceFlags.Recorded) > 0 ? 0x1 : 0,
                       startTime: ToEpochMicroseconds(activity.StartTimeUtc),
                       duration: (long)activity.Duration.TotalMilliseconds * 1000,
                       references: activity.ToJaegerSpanRefs(),
                       tags: jaegerTags.Tags,
                       logs: activity.ToJaegerLogs()));
        }
Exemple #13
0
        private const long UnixEpochMicroseconds = UnixEpochTicks / TicksPerMicrosecond; // 62,135,596,800,000,000

        public static JaegerSpan ToJaegerSpan(this Activity activity)
        {
            var jaegerTags = new TagEnumerationState
            {
                Tags = PooledList <JaegerTag> .Create(),
            };

            activity.EnumerateTags(ref jaegerTags);

            string peerServiceName = null;

            if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer)
            {
                PeerServiceResolver.Resolve(ref jaegerTags, out peerServiceName, out bool addAsTag);

                if (peerServiceName != null && addAsTag)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag(SemanticConventions.AttributePeerService, JaegerTagType.STRING, vStr : peerServiceName));
                }
            }

            // The Span.Kind must translate into a tag.
            // See https://opentracing.io/specification/conventions/
            if (activity.Kind != ActivityKind.Internal)
            {
                string spanKind = null;

                if (activity.Kind == ActivityKind.Server)
                {
                    spanKind = "server";
                }
                else if (activity.Kind == ActivityKind.Client)
                {
                    spanKind = "client";
                }
                else if (activity.Kind == ActivityKind.Consumer)
                {
                    spanKind = "consumer";
                }
                else if (activity.Kind == ActivityKind.Producer)
                {
                    spanKind = "producer";
                }

                if (spanKind != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("span.kind", JaegerTagType.STRING, vStr : spanKind));
                }
            }

            var activitySource = activity.Source;

            if (!string.IsNullOrEmpty(activitySource.Name))
            {
                PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("library.name", JaegerTagType.STRING, vStr : activitySource.Name));

                if (!string.IsNullOrEmpty(activitySource.Version))
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("library.version", JaegerTagType.STRING, vStr : activitySource.Version));
                }
            }

            var traceId      = Int128.Empty;
            var spanId       = Int128.Empty;
            var parentSpanId = Int128.Empty;

            if (activity.IdFormat == ActivityIdFormat.W3C)
            {
                // TODO: The check above should be enforced by the usage of the exporter. Perhaps enforce at higher-level.
                traceId      = new Int128(activity.TraceId);
                spanId       = new Int128(activity.SpanId);
                parentSpanId = new Int128(activity.ParentSpanId);
            }

            return(new JaegerSpan(
                       peerServiceName: peerServiceName,
                       traceIdLow: traceId.Low,
                       traceIdHigh: traceId.High,
                       spanId: spanId.Low,
                       parentSpanId: parentSpanId.Low,
                       operationName: activity.DisplayName,
                       flags: (activity.Context.TraceFlags & ActivityTraceFlags.Recorded) > 0 ? 0x1 : 0,
                       startTime: ToEpochMicroseconds(activity.StartTimeUtc),
                       duration: (long)activity.Duration.TotalMilliseconds * 1000,
                       references: activity.ToJaegerSpanRefs(),
                       tags: jaegerTags.Tags,
                       logs: activity.ToJaegerLogs()));
        }
        public static JaegerSpan ToJaegerSpan(this SpanData span)
        {
            var jaegerTags = new TagState
            {
                Tags = PooledList <JaegerTag> .Create(),
            };

            DictionaryEnumerator <string, object, TagState> .AllocationFreeForEach(
                span.Attributes,
                ref jaegerTags,
                ProcessAttributeRef);

            // Send peer.service for remote calls. If priority = 0 that means peer.service was already included.
            if ((span.Kind == SpanKind.Client || span.Kind == SpanKind.Producer) &&
                jaegerTags.PeerService != null &&
                jaegerTags.PeerServicePriority > 0)
            {
                PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("peer.service", JaegerTagType.STRING, vStr : jaegerTags.PeerService));
            }

            // The Span.Kind must translate into a tag.
            // See https://opentracing.io/specification/conventions/
            if (span.Kind.HasValue)
            {
                string spanKind = null;

                if (span.Kind.Value == SpanKind.Server)
                {
                    spanKind = "server";
                }
                else if (span.Kind.Value == SpanKind.Client)
                {
                    spanKind = "client";
                }
                else if (span.Kind.Value == SpanKind.Consumer)
                {
                    spanKind = "consumer";
                }
                else if (span.Kind.Value == SpanKind.Producer)
                {
                    spanKind = "producer";
                }

                if (spanKind != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("span.kind", JaegerTagType.STRING, vStr : spanKind));
                }
            }

            DictionaryEnumerator <string, object, TagState> .AllocationFreeForEach(
                span.LibraryResource?.Attributes ?? Array.Empty <KeyValuePair <string, object> >(),
                ref jaegerTags,
                ProcessLibraryAttributeRef);

            var status = span.Status;

            if (status.IsValid)
            {
                if (!CanonicalCodeDictionary.TryGetValue(status.CanonicalCode, out string statusCode))
                {
                    statusCode = status.CanonicalCode.ToString();
                    CanonicalCodeDictionary.Add(status.CanonicalCode, statusCode);
                }

                PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag(StatusCode, JaegerTagType.STRING, vStr : statusCode));

                if (status.Description != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag(StatusDescription, JaegerTagType.STRING, vStr : status.Description));
                }
            }

            var traceId      = Int128.Empty;
            var spanId       = Int128.Empty;
            var parentSpanId = Int128.Empty;

            if (span.Context.IsValid)
            {
                traceId      = new Int128(span.Context.TraceId);
                spanId       = new Int128(span.Context.SpanId);
                parentSpanId = new Int128(span.ParentSpanId);
            }

            return(new JaegerSpan(
                       peerServiceName: jaegerTags.PeerService,
                       traceIdLow: traceId.Low,
                       traceIdHigh: traceId.High,
                       spanId: spanId.Low,
                       parentSpanId: parentSpanId.Low,
                       operationName: span.Name,
                       flags: (span.Context.TraceOptions & ActivityTraceFlags.Recorded) > 0 ? 0x1 : 0,
                       startTime: ToEpochMicroseconds(span.StartTimestamp),
                       duration: ToEpochMicroseconds(span.EndTimestamp) - ToEpochMicroseconds(span.StartTimestamp),
                       references: span.Links.ToJaegerSpanRefs(),
                       tags: jaegerTags.Tags,
                       logs: span.Events.ToJaegerLogs()));
        }
        public static JaegerSpan ToJaegerSpan(this SpanData span)
        {
            var jaegerTags = PooledList <JaegerTag> .Create();

            Tuple <string, int> peerService = null;

            foreach (var label in span.Attributes)
            {
                var tag = label.ToJaegerTag();

                if (tag.VStr != null &&
                    PeerServiceKeyResolutionDictionary.TryGetValue(label.Key, out int priority) &&
                    (peerService == null || priority < peerService.Item2))
                {
                    peerService = new Tuple <string, int>(tag.VStr, priority);
                }

                PooledList <JaegerTag> .Add(ref jaegerTags, tag);
            }

            // Send peer.service for remote calls. If priority = 0 that means peer.service was already included.
            if ((span.Kind == SpanKind.Client || span.Kind == SpanKind.Producer) &&
                peerService != null &&
                peerService.Item2 > 0)
            {
                PooledList <JaegerTag> .Add(ref jaegerTags, new JaegerTag("peer.service", JaegerTagType.STRING, vStr : peerService.Item1));
            }

            // The Span.Kind must translate into a tag.
            // See https://opentracing.io/specification/conventions/
            if (span.Kind.HasValue)
            {
                string spanKind = null;

                if (span.Kind.Value == SpanKind.Server)
                {
                    spanKind = "server";
                }
                else if (span.Kind.Value == SpanKind.Client)
                {
                    spanKind = "client";
                }
                else if (span.Kind.Value == SpanKind.Consumer)
                {
                    spanKind = "consumer";
                }
                else if (span.Kind.Value == SpanKind.Producer)
                {
                    spanKind = "producer";
                }

                if (spanKind != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags, new JaegerTag("span.kind", JaegerTagType.STRING, vStr : spanKind));
                }
            }

            foreach (var label in span.LibraryResource?.Attributes ?? Array.Empty <KeyValuePair <string, object> >())
            {
                switch (label.Key)
                {
                case Resource.LibraryNameKey:
                    PooledList <JaegerTag> .Add(ref jaegerTags, label.ToJaegerTag());

                    break;

                case Resource.LibraryVersionKey:
                    PooledList <JaegerTag> .Add(ref jaegerTags, label.ToJaegerTag());

                    break;
                }
            }

            var status = span.Status;

            if (status.IsValid)
            {
                if (!CanonicalCodeDictionary.TryGetValue(status.CanonicalCode, out string statusCode))
                {
                    statusCode = status.CanonicalCode.ToString();
                    CanonicalCodeDictionary.Add(status.CanonicalCode, statusCode);
                }

                PooledList <JaegerTag> .Add(ref jaegerTags, new JaegerTag(StatusCode, JaegerTagType.STRING, vStr : statusCode));

                if (status.Description != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags, new JaegerTag(StatusDescription, JaegerTagType.STRING, vStr : status.Description));
                }
            }

            var traceId      = Int128.Empty;
            var spanId       = Int128.Empty;
            var parentSpanId = Int128.Empty;

            if (span.Context.IsValid)
            {
                traceId      = new Int128(span.Context.TraceId);
                spanId       = new Int128(span.Context.SpanId);
                parentSpanId = new Int128(span.ParentSpanId);
            }

            return(new JaegerSpan(
                       peerServiceName: peerService?.Item1,
                       traceIdLow: traceId.Low,
                       traceIdHigh: traceId.High,
                       spanId: spanId.Low,
                       parentSpanId: parentSpanId.Low,
                       operationName: span.Name,
                       flags: (span.Context.TraceOptions & ActivityTraceFlags.Recorded) > 0 ? 0x1 : 0,
                       startTime: ToEpochMicroseconds(span.StartTimestamp),
                       duration: ToEpochMicroseconds(span.EndTimestamp) - ToEpochMicroseconds(span.StartTimestamp),
                       references: span.Links.ToJaegerSpanRefs(),
                       tags: jaegerTags,
                       logs: span.Events.ToJaegerLogs()));
        }
        private const long UnixEpochMicroseconds = UnixEpochTicks / TicksPerMicrosecond; // 62,135,596,800,000,000

        public static JaegerSpan ToJaegerSpan(this Activity activity)
        {
            var jaegerTags = new TagEnumerationState
            {
                Tags = PooledList <JaegerTag> .Create(),
            };

            activity.EnumerateTags(ref jaegerTags);

            if (activity.Status != ActivityStatusCode.Unset)
            {
                if (activity.Status == ActivityStatusCode.Ok)
                {
                    PooledList <JaegerTag> .Add(
                        ref jaegerTags.Tags,
                        new JaegerTag(SpanAttributeConstants.StatusCodeKey, JaegerTagType.STRING, vStr : "OK"));
                }
                else
                {
                    PooledList <JaegerTag> .Add(
                        ref jaegerTags.Tags,
                        new JaegerTag(SpanAttributeConstants.StatusCodeKey, JaegerTagType.STRING, vStr : "ERROR"));

                    PooledList <JaegerTag> .Add(
                        ref jaegerTags.Tags,
                        new JaegerTag(JaegerErrorFlagTagName, JaegerTagType.BOOL, vBool : true));

                    PooledList <JaegerTag> .Add(
                        ref jaegerTags.Tags,
                        new JaegerTag(SpanAttributeConstants.StatusDescriptionKey, JaegerTagType.STRING, vStr : activity.StatusDescription ?? string.Empty));
                }
            }
            else if (jaegerTags.StatusCode.HasValue && jaegerTags.StatusCode != StatusCode.Unset)
            {
                PooledList <JaegerTag> .Add(
                    ref jaegerTags.Tags,
                    new JaegerTag(
                        SpanAttributeConstants.StatusCodeKey,
                        JaegerTagType.STRING,
                        vStr : StatusHelper.GetTagValueForStatusCode(jaegerTags.StatusCode.Value)));

                if (jaegerTags.StatusCode == StatusCode.Error)
                {
                    PooledList <JaegerTag> .Add(
                        ref jaegerTags.Tags,
                        new JaegerTag(JaegerErrorFlagTagName, JaegerTagType.BOOL, vBool : true));

                    PooledList <JaegerTag> .Add(
                        ref jaegerTags.Tags,
                        new JaegerTag(SpanAttributeConstants.StatusDescriptionKey, JaegerTagType.STRING, vStr : jaegerTags.StatusDescription ?? string.Empty));
                }
            }

            string peerServiceName = null;

            if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer)
            {
                PeerServiceResolver.Resolve(ref jaegerTags, out peerServiceName, out bool addAsTag);

                if (peerServiceName != null && addAsTag)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag(SemanticConventions.AttributePeerService, JaegerTagType.STRING, vStr : peerServiceName));
                }
            }

            // The Span.Kind must translate into a tag.
            // See https://opentracing.io/specification/conventions/
            if (activity.Kind != ActivityKind.Internal)
            {
                string spanKind = null;

                if (activity.Kind == ActivityKind.Server)
                {
                    spanKind = "server";
                }
                else if (activity.Kind == ActivityKind.Client)
                {
                    spanKind = "client";
                }
                else if (activity.Kind == ActivityKind.Consumer)
                {
                    spanKind = "consumer";
                }
                else if (activity.Kind == ActivityKind.Producer)
                {
                    spanKind = "producer";
                }

                if (spanKind != null)
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("span.kind", JaegerTagType.STRING, vStr : spanKind));
                }
            }

            var activitySource = activity.Source;

            if (!string.IsNullOrEmpty(activitySource.Name))
            {
                PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("otel.library.name", JaegerTagType.STRING, vStr : activitySource.Name));

                if (!string.IsNullOrEmpty(activitySource.Version))
                {
                    PooledList <JaegerTag> .Add(ref jaegerTags.Tags, new JaegerTag("otel.library.version", JaegerTagType.STRING, vStr : activitySource.Version));
                }
            }

            var traceId      = Int128.Empty;
            var spanId       = Int128.Empty;
            var parentSpanId = Int128.Empty;

            if (activity.IdFormat == ActivityIdFormat.W3C)
            {
                // TODO: The check above should be enforced by the usage of the exporter. Perhaps enforce at higher-level.
                traceId = new Int128(activity.TraceId);
                spanId  = new Int128(activity.SpanId);
                if (activity.ParentSpanId != default)
                {
                    parentSpanId = new Int128(activity.ParentSpanId);
                }
            }

            return(new JaegerSpan(
                       peerServiceName: peerServiceName,
                       traceIdLow: traceId.Low,
                       traceIdHigh: traceId.High,
                       spanId: spanId.Low,
                       parentSpanId: parentSpanId.Low,
                       operationName: activity.DisplayName,
                       flags: (activity.Context.TraceFlags & ActivityTraceFlags.Recorded) > 0 ? 0x1 : 0,
                       startTime: ToEpochMicroseconds(activity.StartTimeUtc),
                       duration: activity.Duration.Ticks / TicksPerMicrosecond,
                       references: activity.ToJaegerSpanRefs(),
                       tags: jaegerTags.Tags,
                       logs: activity.ToJaegerLogs()));
        }