public void CreateFromString_CreatesIdCorrectly()
        {
            var traceId     = TraceId.CreateRandom();
            var recreatedId = TraceId.CreateFromString(traceId.ToString());

            recreatedId.Should().Be(traceId);
        }
Beispiel #2
0
        public SpanContext Extract <T>(T carrier, Func <T, string, IEnumerable <string> > getter)
        {
            var traceParentCollection = getter(carrier, W3CHeaderNames.TraceParent).ToList();

            if (traceParentCollection.Count != 1)
            {
                Log.Warning("Header {HeaderName} needs exactly 1 value", W3CHeaderNames.TraceParent);
                return(null);
            }

            var traceParentHeader = traceParentCollection.First();
            var traceIdString     = traceParentHeader.Substring(VersionPrefixIdLength, TraceIdLength);
            var traceId           = TraceId.CreateFromString(traceIdString);

            if (traceId == TraceId.Zero)
            {
                Log.Warning("Could not parse {HeaderName} headers: {HeaderValues}", W3CHeaderNames.TraceParent, string.Join(",", traceParentCollection));
                return(null);
            }

            var spanIdString = traceParentHeader.Substring(VersionAndTraceIdLength, SpanIdLength);

            if (!ulong.TryParse(spanIdString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var spanId))
            {
                Log.Warning("Could not parse {HeaderName} headers: {HeaderValues}", W3CHeaderNames.TraceParent, string.Join(",", traceParentCollection));
                return(null);
            }

            var traceStateCollection = getter(carrier, W3CHeaderNames.TraceState);
            var traceState           = ExtractTraceState(traceStateCollection);

            return(spanId == 0 ? null : new SpanContext(traceId, spanId, samplingPriority: null, serviceName: null, traceState));
        }
Beispiel #3
0
        internal void HttpRequestMessage_InjectExtract_Identity_WithParent(IHeadersCollection headers)
        {
            var                    traceId          = TraceId.CreateFromString("52686470458518446744073709551615");
            const ulong            spanId           = 18446744073709551614;
            const SamplingPriority samplingPriority = SamplingPriority.UserKeep;

            var parentContext = new SpanContext(traceId, spanId, samplingPriority);
            var traceContext  = new TraceContext(null)
            {
                SamplingPriority = samplingPriority
            };

            var context = new SpanContext(parentContext, traceContext, null);

            _propagator.Inject(context, headers);

            AssertExpected(headers, B3HttpHeaderNames.B3TraceId, "52686470458518446744073709551615");
            AssertExpected(headers, B3HttpHeaderNames.B3SpanId, context.SpanId.ToString("x16"));
            AssertExpected(headers, B3HttpHeaderNames.B3ParentId, "fffffffffffffffe");
            AssertExpected(headers, B3HttpHeaderNames.B3Flags, "1");
            AssertMissing(headers, B3HttpHeaderNames.B3Sampled);

            var resultContext = _propagator.Extract(headers);

            Assert.NotNull(resultContext);
            Assert.Equal(context.SpanId, resultContext.SpanId);
            Assert.Equal(context.TraceId, resultContext.TraceId);
            Assert.Equal(samplingPriority, resultContext.SamplingPriority);
        }
        internal void Inject_DoNotCreateCorrectTraceStateHeaderIfNotPresent(IHeadersCollection headers)
        {
            var         traceId     = TraceId.CreateFromString("0af7651916cd43dd8448eb211c80319c");
            const ulong spanId      = 67667974448284343;
            var         spanContext = new SpanContext(traceId, spanId, traceState: null);
            var         propagator  = new W3CSpanContextPropagator(new OtelTraceIdConvention());

            propagator.Inject(spanContext, headers);

            headers.GetValues(W3CHeaderNames.TraceState).Should().HaveCount(0);
        }
Beispiel #5
0
        internal void Inject_CreateCorrectTraceStateHeaderIfPresent(IHeadersCollection headers)
        {
            var         traceId     = TraceId.CreateFromString("0af7651916cd43dd8448eb211c80319c");
            const ulong spanId      = 67667974448284343;
            var         spanContext = new SpanContext(traceId, spanId, samplingPriority: null, serviceName: null, "state");
            var         propagator  = W3CSpanContextPropagator.Instance;

            propagator.Inject(spanContext, headers);

            headers.GetValues(W3CHeaderNames.TraceState).Should().Equal("state");
        }
Beispiel #6
0
        internal void Inject_CratesCorrectTraceParentHeader(IHeadersCollection headers)
        {
            var         traceId     = TraceId.CreateFromString("0af7651916cd43dd8448eb211c80319c");
            const ulong spanId      = 67667974448284343;
            var         spanContext = new SpanContext(traceId, spanId, samplingPriority: null);
            var         propagator  = W3CSpanContextPropagator.Instance;

            propagator.Inject(spanContext, headers);

            headers.GetValues(W3CHeaderNames.TraceParent).Should().Equal("00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01");
        }
        public void Equals_WorksCorrectlyBetween64And128BitIds()
        {
            var traceId1 = TraceId.CreateRandomDataDogCompatible();
            var traceId2 = TraceId.CreateFromString(TraceId.Zero.Lower.ToString("x16") + traceId1.Lower.ToString("x16"));

            using (new AssertionScope())
            {
                traceId1.Lower.Should().Be(traceId2.Lower);
                traceId1.Should().NotBe(TraceId.CreateFromString(traceId2.ToString()));
                traceId2.Should().NotBe(TraceId.CreateDataDogCompatibleFromDecimalString(traceId1.ToString()));
                traceId1.GetHashCode().Should().NotBe(traceId2.GetHashCode());
            }
        }
        public void Equals_WorksCorrectlyFor128BitId()
        {
            var traceId1 = TraceId.CreateRandom();
            var traceId2 = TraceId.CreateRandom();

            using (new AssertionScope())
            {
                traceId1.Should().Be(TraceId.CreateFromString(traceId1.ToString()));
                traceId2.Should().Be(TraceId.CreateFromString(traceId2.ToString()));
                traceId1.Should().NotBe(TraceId.CreateFromString(traceId2.ToString()));
                traceId2.Should().NotBe(TraceId.CreateFromString(traceId1.ToString()));
            }
        }
        internal void Extract_ReturnCorrectTraceAndSpanIdInContext(IHeadersCollection headers)
        {
            var propagator = new W3CSpanContextPropagator(new OtelTraceIdConvention());

            headers.Set(W3CHeaderNames.TraceParent, "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01");

            var spanContext = propagator.Extract(headers);

            using (new AssertionScope())
            {
                spanContext.SpanId.Should().Be(67667974448284343);
                spanContext.TraceId.Should().Be(TraceId.CreateFromString("0af7651916cd43dd8448eb211c80319c"));
            }
        }
        internal void InjectExtract_Identity(IHeadersCollection headers)
        {
            var       traceId = TraceId.CreateFromString("52686470458518446744073709551615");
            const int spanId  = 7;
            const SamplingPriority samplingPriority = SamplingPriority.UserKeep;

            var context = new SpanContext(traceId, spanId, samplingPriority);

            _propagator.Inject(context, headers);
            var resultContext = _propagator.Extract(headers);

            Assert.NotNull(resultContext);
            Assert.Equal(context.SpanId, resultContext.SpanId);
            Assert.Equal(context.TraceId, resultContext.TraceId);
            Assert.Equal(context.SamplingPriority, resultContext.SamplingPriority);
        }
        internal void Inject_CreateCorrectTraceStateHeaderIfPresent(IHeadersCollection headers)
        {
            var         traceId     = TraceId.CreateFromString("0af7651916cd43dd8448eb211c80319c");
            const ulong spanId      = 67667974448284343;
            var         spanContext = new SpanContext(traceId, spanId, "state");
            var         propagator  = new W3CSpanContextPropagator(new OtelTraceIdConvention());

            propagator.Inject(spanContext, headers);

            using (new AssertionScope())
            {
                headers.GetValues(W3CHeaderNames.TraceState).Should().HaveCount(1);
                headers.GetValues(W3CHeaderNames.TraceState).Should().BeEquivalentTo(new List <string> {
                    "state"
                });
            }
        }
Beispiel #12
0
        internal void Extract_InvalidSpanId(IHeadersCollection headers, string spanId)
        {
            var traceId = TraceId.CreateFromString("52686470458518446744073709551615");
            const SamplingPriority samplingPriority = SamplingPriority.UserKeep;

            InjectContext(
                headers,
                traceId.ToString(),
                spanId,
                ((int)samplingPriority).ToString(CultureInfo.InvariantCulture));
            var resultContext = _propagator.Extract(headers);

            Assert.NotNull(resultContext);
            Assert.Equal(traceId, resultContext.TraceId);
            Assert.Equal(default(ulong), resultContext.SpanId);
            Assert.Equal(samplingPriority, resultContext.SamplingPriority);
        }
        internal void Extract_InvalidSamplingPriority(IHeadersCollection headers, string samplingPriority)
        {
            var         traceId = TraceId.CreateFromString("52686470458518446744073709551615");
            const ulong spanId  = 7;

            InjectContext(
                headers,
                traceId.ToString(),
                spanId.ToString("x16", CultureInfo.InvariantCulture),
                samplingPriority);

            var resultContext = _propagator.Extract(headers);

            Assert.NotNull(resultContext);
            Assert.Equal(traceId, resultContext.TraceId);
            Assert.Equal(spanId, resultContext.SpanId);
            Assert.Null(resultContext.SamplingPriority);
        }
        internal static void Contains(this log4net.Core.LoggingEvent logEvent, TraceId traceId, ulong spanId, string service, string environment)
        {
            // First, verify that the properties are attached to the LogEvent
            Assert.Contains(CorrelationIdentifier.TraceIdKey, logEvent.Properties.GetKeys());
            Assert.Equal(traceId, TraceId.CreateFromString(logEvent.Properties[CorrelationIdentifier.TraceIdKey].ToString()));
            Assert.Contains(CorrelationIdentifier.SpanIdKey, logEvent.Properties.GetKeys());
            Assert.Equal <ulong>(spanId, Convert.ToUInt64(logEvent.Properties[CorrelationIdentifier.SpanIdKey].ToString(), 16));
            Assert.Contains(CorrelationIdentifier.ServiceNameKey, logEvent.Properties.GetKeys());
            Assert.Equal(service, logEvent.Properties[CorrelationIdentifier.ServiceNameKey].ToString());
            Assert.Contains(CorrelationIdentifier.ServiceEnvironmentKey, logEvent.Properties.GetKeys());
            Assert.Equal(environment, logEvent.Properties[CorrelationIdentifier.ServiceEnvironmentKey].ToString());

            // Second, verify that the message formatting correctly encloses the
            // values in quotes, since they are string values
            var    layout           = new Log4NetLogProviderTests.Log4NetJsonLayout();
            string formattedMessage = layout.Format(logEvent);

            Assert.Contains(string.Format(Log4NetExpectedStringFormat, CorrelationIdentifier.TraceIdKey, traceId), formattedMessage);
            Assert.Contains(string.Format(Log4NetExpectedStringFormat, CorrelationIdentifier.SpanIdKey, spanId), formattedMessage);
        }
Beispiel #15
0
        internal void WebRequest_InjectExtract_Identity(IHeadersCollection headers)
        {
            var       traceId = TraceId.CreateFromString("52686470458518446744073709551615");
            const int spanId  = 2147483646;
            const SamplingPriority samplingPriority = SamplingPriority.AutoReject;

            var context = new SpanContext(traceId, spanId, samplingPriority);

            _propagator.Inject(context, headers);

            AssertExpected(headers, B3HttpHeaderNames.B3TraceId, "52686470458518446744073709551615");
            AssertExpected(headers, B3HttpHeaderNames.B3SpanId, "000000007ffffffe");
            AssertExpected(headers, B3HttpHeaderNames.B3Sampled, "0");
            AssertMissing(headers, B3HttpHeaderNames.B3ParentId);
            AssertMissing(headers, B3HttpHeaderNames.B3Flags);

            var resultContext = _propagator.Extract(headers);

            Assert.NotNull(resultContext);
            Assert.Equal(context.SpanId, resultContext.SpanId);
            Assert.Equal(context.TraceId, resultContext.TraceId);
            Assert.Equal(context.SamplingPriority, resultContext.SamplingPriority);
        }
        internal static void Contains(this Serilog.Events.LogEvent logEvent, Scope scope)
        {
            string SanitizedProperty(string correlationIdentifier)
            {
                return(logEvent.Properties[correlationIdentifier].ToString().Trim(new[] { '\"' }));
            }

            var traceId = scope.Span.TraceId;
            var spanId  = scope.Span.SpanId;

            // First, verify that the properties are attached to the LogEvent
            Assert.True(logEvent.Properties.ContainsKey(CorrelationIdentifier.TraceIdKey));
            Assert.Equal(traceId, TraceId.CreateFromString(SanitizedProperty(CorrelationIdentifier.TraceIdKey)));
            Assert.True(logEvent.Properties.ContainsKey(CorrelationIdentifier.SpanIdKey));
            Assert.Equal <ulong>(spanId, Convert.ToUInt64(SanitizedProperty(CorrelationIdentifier.SpanIdKey), fromBase: 16));
            Assert.True(logEvent.Properties.ContainsKey(CorrelationIdentifier.ServiceNameKey));
            Assert.Equal(ServiceName, SanitizedProperty(CorrelationIdentifier.ServiceNameKey));
            Assert.True(logEvent.Properties.ContainsKey(CorrelationIdentifier.ServiceEnvironmentKey));
            Assert.Equal(ServiceEnvironment, SanitizedProperty(CorrelationIdentifier.ServiceEnvironmentKey));

            // Second, verify that the message formatting correctly encloses the
            // values in quotes, since they are string values

            // Use the built-in formatting to render the message like the console output would,
            // but this must write to a TextWriter so use a StringWriter/StringBuilder to shuttle
            // the message to our in-memory list
            const string outputTemplate = "{Message}|{Properties}";
            var          textFormatter  = new MessageTemplateTextFormatter(outputTemplate, CultureInfo.InvariantCulture);
            var          sw             = new StringWriter(new StringBuilder());

            textFormatter.Format(logEvent, sw);
            var formattedMessage = sw.ToString();

            Assert.Contains(string.Format(SerilogExpectedStringFormat, CorrelationIdentifier.TraceIdKey, traceId), formattedMessage);
            Assert.Contains(string.Format(SerilogExpectedStringFormat, CorrelationIdentifier.SpanIdKey, spanId), formattedMessage);
        }
 public TraceId CreateFromString(string id) => TraceId.CreateFromString(id);
        public bool TryExtract <TCarrier, TCarrierGetter>(TCarrier carrier, TCarrierGetter carrierGetter, out SpanContext?spanContext)
            where TCarrierGetter : struct, ICarrierGetter <TCarrier>
        {
            spanContext = null;

            var brValue = ParseUtility.ParseString(carrier, carrierGetter, B3)?.Trim();

            if (!string.IsNullOrEmpty(brValue))
            {
                // We found a trace parent (we are reading from the Http Headers)

                // 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90
                // 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1
                // e457b5a2e4d86bd1-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90
                // e457b5a2e4d86bd1-e457b5a2e4d86bd1-1
                if (brValue !.Length != 68 && brValue !.Length != 51 &&
                    brValue !.Length != 52 && brValue !.Length != 35)
                {
                    return(false);
                }

#if NETCOREAPP
                ReadOnlySpan <char> rawTraceId = null;
                ReadOnlySpan <char> rawSpanId  = null;
                char rawSampled = '0';
                if (brValue.Length > 50 && brValue[32] == '-' && brValue[49] == '-')
                {
                    // 128 bits trace id
                    rawTraceId = brValue.AsSpan(0, 32);
                    rawSpanId  = brValue.AsSpan(33, 16);
                    rawSampled = brValue[50];
                }
                else if (brValue.Length > 34 && brValue[16] == '-' && brValue[33] == '-')
                {
                    // 64 bits trace id
                    rawTraceId = brValue.AsSpan(0, 16);
                    rawSpanId  = brValue.AsSpan(17, 16);
                    rawSampled = brValue[34];
                }
                else
                {
                    return(false);
                }

                var traceId          = TraceId.CreateFromString(rawTraceId.ToString());
                var parentId         = ParseUtility.ParseFromHexOrDefault(rawSpanId);
                var samplingPriority = rawSampled == '1' ? 1 : 0;

                spanContext = new SpanContext(traceId, parentId, samplingPriority, serviceName: null, null, rawTraceId.ToString(), rawSpanId.ToString());
#else
                string?rawTraceId = null;
                string?rawSpanId  = null;
                char   rawSampled = '0';
                if (brValue.Length > 50 && brValue[32] == '-' && brValue[49] == '-')
                {
                    // 128 bits trace id
                    rawTraceId = brValue.Substring(0, 32);
                    rawSpanId  = brValue.Substring(33, 16);
                    rawSampled = brValue[50];
                }
                else if (brValue.Length > 34 && brValue[16] == '-' && brValue[33] == '-')
                {
                    // 64 bits trace id
                    rawTraceId = brValue.Substring(0, 16);
                    rawSpanId  = brValue.Substring(17, 16);
                    rawSampled = brValue[34];
                }
                else
                {
                    return(false);
                }

                var traceId          = TraceId.CreateFromString(rawTraceId);
                var parentId         = ParseUtility.ParseFromHexOrDefault(rawSpanId);
                var samplingPriority = rawSampled == '1' ? 1 : 0;

                spanContext = new SpanContext(traceId, parentId, samplingPriority, serviceName: null, null, rawTraceId, rawSpanId);
#endif

                return(true);
            }

            return(false);
        }
        public void Equals_WorksCorrectly()
        {
            var traceId1 = TraceId.CreateRandom();

            traceId1.Should().Be(TraceId.CreateFromString(traceId1.ToString()));
        }
        public bool TryExtract <TCarrier, TCarrierGetter>(TCarrier carrier, TCarrierGetter carrierGetter, out SpanContext?spanContext)
            where TCarrierGetter : struct, ICarrierGetter <TCarrier>
        {
            spanContext = null;

            var traceParent = ParseUtility.ParseString(carrier, carrierGetter, TraceParent)?.Trim();

            if (!string.IsNullOrEmpty(traceParent))
            {
                // We found a trace parent (we are reading from the Http Headers)

                /* (https://www.w3.org/TR/trace-context/)
                 *  Valid traceparent when caller sampled this request:
                 *
                 *  Value = 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
                 *  base16(version) = 00
                 *  base16(trace-id) = 4bf92f3577b34da6a3ce929d0e0e4736
                 *  base16(parent-id) = 00f067aa0ba902b7
                 *  base16(trace-flags) = 01  // sampled
                 *  Valid traceparent when caller didn’t sample this request:
                 *
                 *  Value = 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00
                 *  base16(version) = 00
                 *  base16(trace-id) = 4bf92f3577b34da6a3ce929d0e0e4736
                 *  base16(parent-id) = 00f067aa0ba902b7
                 *  base16(trace-flags) = 00  // not sampled
                 */

                if (traceParent !.Length != 55 || traceParent[2] != '-' || traceParent[35] != '-' || traceParent[52] != '-')
                {
                    return(false);
                }

                char w3cSampled = traceParent[54];
                if (traceParent[53] != '0' || (w3cSampled != '0' && w3cSampled != '1'))
                {
                    return(false);
                }

                var samplingPriority = w3cSampled == '0' ? 0 : 1;

#if NETCOREAPP
                var w3cTraceId = traceParent.AsSpan(3, 32);
                var w3cSpanId  = traceParent.AsSpan(36, 16);
                var traceId    = TraceId.CreateFromString(w3cTraceId.ToString());
                if (traceId == TraceId.Zero)
                {
                    return(false);
                }

                var parentId = ParseUtility.ParseFromHexOrDefault(w3cSpanId);

                spanContext = new SpanContext(traceId, parentId, samplingPriority, serviceName: null, null, w3cTraceId.ToString(), w3cSpanId.ToString());
#else
                var w3cTraceId = traceParent.Substring(3, 32);
                var w3cSpanId  = traceParent.Substring(36, 16);

                if (!IsValidTraceId(w3cTraceId, out var traceId))
                {
                    return(false);
                }

                var parentId = ParseUtility.ParseFromHexOrDefault(w3cSpanId);

                spanContext = new SpanContext(traceId, parentId, samplingPriority, serviceName: null, null, w3cTraceId, w3cSpanId);
#endif

                return(true);
            }

            return(false);
        }