public static TraceTagCollection ParseFromPropagationHeader(string?propagationHeader)
        {
            if (string.IsNullOrEmpty(propagationHeader))
            {
                return(new TraceTagCollection());
            }

            var tags                = propagationHeader !.Split(TagPairSeparators, StringSplitOptions.RemoveEmptyEntries);
            var tagList             = new List <KeyValuePair <string, string> >(tags.Length);
            var cacheOriginalHeader = true;

            foreach (var tag in tags)
            {
                // the shortest tag has the "_dd.p." prefix, a 1-character key, and 1-character value (e.g. "_dd.p.a=b")
                if (tag.Length >= MinimumPropagationHeaderLength &&
                    tag.StartsWith(PropagatedTagPrefix, StringComparison.Ordinal))
                {
                    // NOTE: the first equals sign is the separator between key/value, but the tag value can contain
                    // additional equals signs, so make sure we only split on the _first_ one. For example,
                    // the "_dd.p.upstream_services" tag will have base64-encoded strings which use '=' for padding.
                    var separatorIndex = tag.IndexOf(KeyValueSeparator);

                    // "_dd.p.a=b"
                    //         ⬆   separator must be at index 7 or higher and before the end of string
                    //  012345678
                    if (separatorIndex > PropagatedTagPrefixLength &&
                        separatorIndex < tag.Length - 1)
                    {
                        // TODO: implement something like StringSegment to avoid allocating new strings?
                        var key   = tag.Substring(0, separatorIndex);
                        var value = tag.Substring(separatorIndex + 1);
                        tagList.Add(new KeyValuePair <string, string>(key, value));
                    }
                    else
                    {
                        // skip invalid tag
                        cacheOriginalHeader = false;
                    }
                }
                else
                {
                    // skip invalid tag
                    cacheOriginalHeader = false;
                }
            }

            var traceTags = new TraceTagCollection(tagList);

            if (cacheOriginalHeader)
            {
                // we didn't skip any invalid tag, we can cache the original header string
                traceTags._cachedPropagationHeader = propagationHeader;
            }

            return(traceTags);
        }
Beispiel #2
0
        private int WriteTraceTags(ref byte[] bytes, ref int offset, TraceTagCollection tags, ITagProcessor[] tagProcessors)
        {
            int count = 0;

            if (tags != null)
            {
                lock (tags)
                {
                    count += tags.Count;

                    // don't cast to IEnumerable so we can use the struct enumerator from List<T>
                    foreach (var tag in tags)
                    {
                        WriteTag(ref bytes, ref offset, tag.Key, tag.Value, tagProcessors);
                    }
                }
            }

            return(count);
        }