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); }
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); }