예제 #1
0
 private SpanContext(ITraceId traceId, ISpanId spanId, TraceOptions traceOptions, Tracestate tracestate)
 {
     this.TraceId      = traceId;
     this.SpanId       = spanId;
     this.TraceOptions = traceOptions;
     this.Tracestate   = tracestate;
 }
예제 #2
0
        private static bool MakeSamplingDecision(
            SpanContext parent,
            string name,
            ISampler sampler,
            IEnumerable <ISpan> parentLinks,
            ITraceId traceId,
            ISpanId spanId,
            ITraceParams activeTraceParams)
        {
            // If users set a specific sampler in the SpanBuilder, use it.
            if (sampler != null)
            {
                return(sampler.ShouldSample(parent, traceId, spanId, name, parentLinks));
            }

            // Use the default sampler if this is a root Span or this is an entry point Span (has remote
            // parent).
            if (parent == null || !parent.IsValid)
            {
                return(activeTraceParams
                       .Sampler
                       .ShouldSample(parent, traceId, spanId, name, parentLinks));
            }

            // Parent is always different than null because otherwise we use the default sampler.
            return(parent.TraceOptions.IsSampled || IsAnyParentLinkSampled(parentLinks));
        }
예제 #3
0
 private Link(ITraceId traceId, ISpanId spanId, LinkType type, IDictionary <string, IAttributeValue> attributes)
 {
     this.TraceId    = traceId ?? throw new ArgumentNullException(nameof(traceId));
     this.SpanId     = spanId ?? throw new ArgumentNullException(nameof(spanId));
     this.Type       = type;
     this.Attributes = attributes ?? throw new ArgumentNullException(nameof(attributes));
 }
예제 #4
0
        public bool ShouldSample(SpanContext parentContext, ITraceId traceId, ISpanId spanId, string name, IEnumerable <ISpan> parentLinks)
        {
            // If the parent is sampled keep the sampling decision.
            if (parentContext != null && parentContext.TraceOptions.IsSampled)
            {
                return(true);
            }

            if (parentLinks != null)
            {
                // If any parent link is sampled keep the sampling decision.
                foreach (ISpan parentLink in parentLinks)
                {
                    if (parentLink.Context.TraceOptions.IsSampled)
                    {
                        return(true);
                    }
                }
            }

            // Always sample if we are within probability range. This is true even for child spans (that
            // may have had a different sampling decision made) to allow for different sampling policies,
            // and dynamic increases to sampling probabilities for debugging purposes.
            // Note use of '<' for comparison. This ensures that we never sample for probability == 0.0,
            // while allowing for a (very) small chance of *not* sampling if the id == Long.MAX_VALUE.
            // This is considered a reasonable tradeoff for the simplicity/performance requirements (this
            // code is executed in-line for every Span creation).
            return(Math.Abs(traceId.LowerLong) < this.IdUpperBound);
        }
예제 #5
0
 public SamplersTest()
 {
     traceId               = TraceId.GenerateRandomId(random);
     parentSpanId          = SpanId.GenerateRandomId(random);
     spanId                = SpanId.GenerateRandomId(random);
     sampledSpanContext    = SpanContext.Create(traceId, parentSpanId, TraceOptions.Builder().SetIsSampled(true).Build(), Tracestate.Empty);
     notSampledSpanContext = SpanContext.Create(traceId, parentSpanId, TraceOptions.Default, Tracestate.Empty);
     sampledSpan           = new TestSpan(sampledSpanContext, SpanOptions.RecordEvents);
 }
예제 #6
0
 public SamplersTest()
 {
     traceId               = TraceId.GenerateRandomId(random);
     parentSpanId          = SpanId.GenerateRandomId(random);
     spanId                = SpanId.GenerateRandomId(random);
     sampledSpanContext    = SpanContext.Create(traceId, parentSpanId, TraceOptions.Builder().SetIsSampled(true).Build());
     notSampledSpanContext = SpanContext.Create(traceId, parentSpanId, TraceOptions.DEFAULT);
     sampledSpan           = new NoopSpan(sampledSpanContext, SpanOptions.RECORD_EVENTS);
 }
예제 #7
0
        public async Task HttpDepenenciesCollectorInjectsHeadersAsync()
        {
            var startEndHandler = new Mock <IStartEndHandler>();

            var serverLifeTime = TestServer.RunServer(
                (ctx) =>
            {
                ctx.Response.StatusCode = 200;
                ctx.Response.OutputStream.Close();
            },
                out string host,
                out int port);

            var url = $"http://{host}:{port}/";

            ITraceId expectedTraceId = TraceId.Invalid;
            ISpanId  expectedSpanId  = SpanId.Invalid;

            using (serverLifeTime)
            {
                var tracer = new Tracer(new RandomGenerator(), startEndHandler.Object, new DateTimeOffsetClock(), new TraceConfig());

                var tf = new Mock <ITextFormat>();
                tf
                .Setup(m => m.Inject <HttpRequestMessage>(It.IsAny <ISpanContext>(), It.IsAny <HttpRequestMessage>(), It.IsAny <Action <HttpRequestMessage, string, string> >()))
                .Callback((ISpanContext sc, HttpRequestMessage obj, Action <HttpRequestMessage, string, string> setter) =>
                {
                    expectedTraceId = sc.TraceId;
                    expectedSpanId  = sc.SpanId;
                });

                var propagationComponent = new Mock <IPropagationComponent>();
                propagationComponent.SetupGet(m => m.TextFormat).Returns(tf.Object);

                using (var dc = new DependenciesCollector(new DependenciesCollectorOptions(), tracer, Samplers.AlwaysSample, propagationComponent.Object))
                {
                    using (var c = new HttpClient())
                    {
                        var request = new HttpRequestMessage
                        {
                            RequestUri = new Uri(url),
                            Method     = new HttpMethod("GET"),
                        };

                        await c.SendAsync(request);
                    }
                }
            }

            Assert.Equal(2, startEndHandler.Invocations.Count); // begin and end was called
            var spanData = ((Span)startEndHandler.Invocations[1].Arguments[0]).ToSpanData();

            Assert.Equal(expectedTraceId, spanData.Context.TraceId);
            Assert.Equal(expectedSpanId, spanData.Context.SpanId);
        }
        private string EncodeTraceId(ITraceId traceId)
        {
            var id = traceId.ToLowerBase16();

            if (id.Length > 16 && this.options.UseShortTraceIds)
            {
                id = id.Substring(id.Length - 16, 16);
            }

            return(id);
        }
예제 #9
0
        public int CompareTo(ITraceId other)
        {
            TraceId that = other as TraceId;

            for (int i = 0; i < SIZE; i++)
            {
                if (bytes[i] != that.bytes[i])
                {
                    sbyte b1 = (sbyte)bytes[i];
                    sbyte b2 = (sbyte)that.bytes[i];

                    return(b1 < b2 ? -1 : 1);
                }
            }
            return(0);
        }
예제 #10
0
        public override ISpanContext FromByteArray(byte[] bytes)
        {
            if (bytes == null)
            {
                throw new ArgumentNullException(nameof(bytes));
            }

            if (bytes.Length == 0 || bytes[0] != VERSION_ID)
            {
                throw new SpanContextParseException("Unsupported version.");
            }

            ITraceId     traceId      = TraceId.INVALID;
            ISpanId      spanId       = SpanId.INVALID;
            TraceOptions traceOptions = TraceOptions.DEFAULT;

            int pos = 1;

            try
            {
                if (bytes.Length > pos && bytes[pos] == TRACE_ID_FIELD_ID)
                {
                    traceId = TraceId.FromBytes(bytes, pos + ID_SIZE);
                    pos    += ID_SIZE + TraceId.SIZE;
                }

                if (bytes.Length > pos && bytes[pos] == SPAN_ID_FIELD_ID)
                {
                    spanId = SpanId.FromBytes(bytes, pos + ID_SIZE);
                    pos   += ID_SIZE + SpanId.SIZE;
                }

                if (bytes.Length > pos && bytes[pos] == TRACE_OPTION_FIELD_ID)
                {
                    traceOptions = TraceOptions.FromBytes(bytes, pos + ID_SIZE);
                }

                return(SpanContext.Create(traceId, spanId, traceOptions));
            }
            catch (Exception e)
            {
                throw new SpanContextParseException("Invalid input.", e);
            }
        }
예제 #11
0
        public override ISpanContext FromByteArray(byte[] bytes)
        {
            if (bytes == null)
            {
                throw new ArgumentNullException(nameof(bytes));
            }

            if (bytes.Length == 0 || bytes[0] != VersionId)
            {
                throw new SpanContextParseException("Unsupported version.");
            }

            ITraceId     traceId      = TraceId.Invalid;
            ISpanId      spanId       = SpanId.Invalid;
            TraceOptions traceOptions = TraceOptions.Default;

            int pos = 1;

            try
            {
                if (bytes.Length > pos && bytes[pos] == TraceIdFieldId)
                {
                    traceId = TraceId.FromBytes(bytes, pos + IdSize);
                    pos    += IdSize + TraceId.Size;
                }

                if (bytes.Length > pos && bytes[pos] == SpanIdFieldId)
                {
                    spanId = SpanId.FromBytes(bytes, pos + IdSize);
                    pos   += IdSize + SpanId.Size;
                }

                if (bytes.Length > pos && bytes[pos] == TraceOptionsFieldId)
                {
                    traceOptions = TraceOptions.FromBytes(bytes, pos + IdSize);
                }

                return(SpanContext.Create(traceId, spanId, traceOptions, Tracestate.Empty));
            }
            catch (Exception e)
            {
                throw new SpanContextParseException("Invalid input.", e);
            }
        }
예제 #12
0
        private Link(ITraceId traceId, ISpanId spanId, LinkType type, IDictionary <string, IAttributeValue> attributes)
        {
            if (traceId == null)
            {
                throw new ArgumentNullException(nameof(traceId));
            }
            if (spanId == null)
            {
                throw new ArgumentNullException(nameof(spanId));
            }
            if (attributes == null)
            {
                throw new ArgumentNullException(nameof(attributes));
            }

            TraceId    = traceId;
            SpanId     = spanId;
            Type       = type;
            Attributes = attributes;
        }
예제 #13
0
        public void StartRemoteChildSpan_WithProbabilitySamplerDefaultSampler()
        {
            var configMock = Mock.Get <ITraceConfig>(traceConfig);

            configMock.Setup((c) => c.ActiveTraceParams).Returns(TraceParams.DEFAULT);

            // This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long
            // is not less than probability * Long.MAX_VALUE;
            ITraceId traceId =
                TraceId.FromBytes(
                    new byte[]
            {
                (byte)0x8F,
                (byte)0xFF,
                (byte)0xFF,
                (byte)0xFF,
                (byte)0xFF,
                (byte)0xFF,
                (byte)0xFF,
                (byte)0xFF,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0
            });

            // If parent is sampled then the remote child must be sampled.
            ISpan childSpan =
                SpanBuilder.CreateWithRemoteParent(
                    SPAN_NAME,
                    SpanContext.Create(
                        traceId,
                        SpanId.GenerateRandomId(randomHandler),
                        TraceOptions.Builder().SetIsSampled(true).Build()),
                    spanBuilderOptions)
                .StartSpan();

            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(traceId, childSpan.Context.TraceId);
            Assert.True(childSpan.Context.TraceOptions.IsSampled);
            childSpan.End();

            Assert.Equal(TraceParams.DEFAULT, traceConfig.ActiveTraceParams);

            // If parent is not sampled then the remote child must be not sampled.
            childSpan =
                SpanBuilder.CreateWithRemoteParent(
                    SPAN_NAME,
                    SpanContext.Create(
                        traceId,
                        SpanId.GenerateRandomId(randomHandler),
                        TraceOptions.DEFAULT),
                    spanBuilderOptions)
                .StartSpan();
            Assert.True(childSpan.Context.IsValid);
            Assert.Equal(traceId, childSpan.Context.TraceId);
            Assert.False(childSpan.Context.TraceOptions.IsSampled);
            childSpan.End();
        }
예제 #14
0
 private SpanContext(ITraceId traceId, ISpanId spanId, TraceOptions traceOptions)
 {
     TraceId      = traceId;
     SpanId       = spanId;
     TraceOptions = traceOptions;
 }
예제 #15
0
 public static ISpanContext Create(ITraceId traceId, ISpanId spanId, TraceOptions traceOptions)
 {
     return(new SpanContext(traceId, spanId, traceOptions));
 }
 public bool ShouldSample(ISpanContext parentContext, bool hasRemoteParent, ITraceId traceId, ISpanId spanId, string name, IList <ISpan> parentLinks)
 {
     return(false);
 }
예제 #17
0
 public bool ShouldSample(ISpanContext parentContext, bool hasRemoteParent, ITraceId traceId, ISpanId spanId, string name, IEnumerable <ISpan> parentLinks)
 {
     throw new System.NotImplementedException();
 }
예제 #18
0
        private bool TryExtractTraceparent(string traceparent, out ITraceId traceId, out ISpanId spanId, out TraceOptions traceoptions)
        {
            // from https://github.com/w3c/distributed-tracing/blob/master/trace_context/HTTP_HEADER_FORMAT.md
            // traceparent: 00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01

            traceId      = TraceId.Invalid;
            spanId       = SpanId.Invalid;
            traceoptions = TraceOptions.Default;
            var bestAttempt = false;

            if (string.IsNullOrWhiteSpace(traceparent))
            {
                return(false);
            }

            // if version does not end with delimeter
            if (traceparent.Length < VersionPrefixIdLength || traceparent[VersionPrefixIdLength - 1] != '-')
            {
                return(false);
            }

            // or version is not a hex (will throw)
            var versionArray = Arrays.StringToByteArray(traceparent, 0, VersionLength);

            if (versionArray[0] == 255)
            {
                return(false);
            }

            if (versionArray[0] > 0)
            {
                // expected version is 00
                // for higher versions - best attempt parsing of trace id, span id, etc.
                bestAttempt = true;
            }

            if (traceparent.Length < VersionAndTraceIdLength || traceparent[VersionAndTraceIdLength - 1] != '-')
            {
                return(false);
            }

            try
            {
                traceId = TraceId.FromBytes(Arrays.StringToByteArray(traceparent, VersionPrefixIdLength, TraceIdLength));
            }
            catch (ArgumentOutOfRangeException)
            {
                // it's ok to still parse tracestate
                return(false);
            }

            if (traceparent.Length < VersionAndTraceIdAndSpanIdLength || traceparent[VersionAndTraceIdAndSpanIdLength - 1] != '-')
            {
                return(false);
            }

            try
            {
                spanId = SpanId.FromBytes(Arrays.StringToByteArray(traceparent, VersionAndTraceIdLength, SpanIdLength));
            }
            catch (ArgumentOutOfRangeException)
            {
                // it's ok to still parse tracestate
                return(false);
            }

            if (traceparent.Length < VersionAndTraceIdAndSpanIdLength + OptionsLength)
            {
                return(false);
            }

            byte[] optionsArray;

            try
            {
                optionsArray = Arrays.StringToByteArray(traceparent, VersionAndTraceIdAndSpanIdLength, OptionsLength);
            }
            catch (ArgumentOutOfRangeException)
            {
                // it's ok to still parse tracestate
                return(false);
            }

            if ((optionsArray[0] | 1) == 1)
            {
                traceoptions = TraceOptions.Builder().SetIsSampled(true).Build();
            }

            if ((!bestAttempt) && (traceparent.Length != VersionAndTraceIdAndSpanIdLength + OptionsLength))
            {
                return(false);
            }

            if (bestAttempt)
            {
                if ((traceparent.Length > VersionAndTraceIdAndSpanIdLength + OptionsLength) &&
                    (traceparent[VersionAndTraceIdAndSpanIdLength + OptionsLength] != '-'))
                {
                    return(false);
                }
            }

            return(true);
        }
예제 #19
0
        public void ProbabilitySampler_SampleBasedOnTraceId()
        {
            ISampler defaultProbability = ProbabilitySampler.Create(0.0001);
            // This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long
            // is not less than probability * Long.MAX_VALUE;
            ITraceId notSampledtraceId =
                TraceId.FromBytes(
                    new byte[]
            {
                0x8F,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
            });

            Assert.False(
                defaultProbability.ShouldSample(
                    null,
                    notSampledtraceId,
                    SpanId.GenerateRandomId(random),
                    SPAN_NAME,
                    new List <ISpan>()));
            // This traceId will be sampled by the ProbabilitySampler because the first 8 bytes as long
            // is less than probability * Long.MAX_VALUE;
            ITraceId sampledtraceId =
                TraceId.FromBytes(
                    new byte[]
            {
                0x00,
                0x00,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0xFF,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
            });

            Assert.True(
                defaultProbability.ShouldSample(
                    null,
                    sampledtraceId,
                    SpanId.GenerateRandomId(random),
                    SPAN_NAME,
                    new List <ISpan>()));
        }
 public bool ShouldSample(SpanContext parentContext, ITraceId traceId, ISpanId spanId, string name, IEnumerable <ISpan> parentLinks)
 {
     return(false);
 }
예제 #21
0
 public bool ShouldSample(ISpanContext parentContext, bool hasRemoteParent, ITraceId traceId, ISpanId spanId, string name, IEnumerable <ISpan> parentLinks)
 {
     return(true);
 }