示例#1
0
        public static ThriftSpan ConvertSpan(Span span)
        {
            var context   = span.Context;
            var startTime = span.StartTimestampUtc.ToUnixTimeMicroseconds();
            var duration  = (span.FinishTimestampUtc?.ToUnixTimeMicroseconds() - startTime) ?? 0;

            var  references       = span.GetReferences();
            bool oneChildOfParent = references.Count == 1 && string.Equals(References.ChildOf, references[0].Type, StringComparison.Ordinal);

            var thriftSpan = new ThriftSpan(
                context.TraceId.Low,
                context.TraceId.High,
                context.SpanId,
                oneChildOfParent ? context.ParentId : 0L,
                span.OperationName,
                (byte)context.Flags,
                startTime,
                duration
                )
            {
                References = oneChildOfParent ? new List <ThriftReference>() : BuildReferences(references),
                Tags       = BuildTags(span.GetTags()),
                Logs       = BuildLogs(span.GetLogs()),
            };

            return(thriftSpan);
        }
        internal static JaegerSpan BuildJaegerThriftSpan(ILetsTraceSpan span)
        {
            var context   = (ILetsTraceSpanContext)span.Context;
            var startTime = span.StartTimestamp.ToUnixTimeMicroseconds();
            var duration  = span.FinishTimestamp == null ?
                            0
                : span.FinishTimestamp.GetValueOrDefault().ToUnixTimeMicroseconds() - span.StartTimestamp.ToUnixTimeMicroseconds();

            var jaegerSpan = new JaegerSpan(
                (long)context.TraceId.Low,
                (long)context.TraceId.High,
                context.SpanId,
                context.ParentId,
                span.OperationName,
                0,
                startTime,
                duration
                );

            span.References.Select(r => r);
            foreach (var tag in span.Tags)
            {
                tag.Value.Key = tag.Key;
                tag.Value.Marshal(jaegerSpan.Tags);
            }
            jaegerSpan.Logs       = span.Logs.Select(BuildJaegerLog).ToList();
            jaegerSpan.References = span.References.Select(BuildJaegerReference).Where(r => r != null).ToList();

            return(jaegerSpan);
        }
示例#3
0
 public int BufferItem(JaegerSpan item)
 {
     lock (_buffer)
     {
         _buffer.Add(item);
         return(_buffer.Count);
     }
 }
示例#4
0
        public void BufferItem_ShouldReturnCountAfterAddingItem()
        {
            var sender = new TestingSender();
            var item   = new JaegerSpan();

            Assert.Equal(1, sender.BufferItem(item));
            Assert.Equal(2, sender.BufferItem(item));
            Assert.Equal(2, sender.Buffer.Count);
        }
示例#5
0
        public Task <int> AppendAsync(Span span, CancellationToken cancellationToken)
        {
            _blocker.Wait();

            ThriftSpan thriftSpan = JaegerThriftSpanConverter.ConvertSpan(span);

            _appended.Add(thriftSpan);
            _received.Add(thriftSpan);
            return(Task.FromResult(0));
        }
示例#6
0
 protected int CalculateSpanSize(ThriftSpan span)
 {
     try
     {
         return(GetSize(span));
     }
     catch (Exception ex)
     {
         throw new SenderException("ThriftSender failed writing Span to memory buffer.", ex, 1);
     }
 }
示例#7
0
        /// <inheritdoc />
        /// <summary>
        /// ProtocolAppendLogicAsync contains the specific logic for appending spans to be
        /// sent over HTTP. It will keep track of the number of spans and send them once
        /// over the batchSize.
        /// </summary>
        /// <param name="span">The span serialized in Jaeger Thrift</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal override async Task <int> ProtocolAppendLogicAsync(JaegerSpan span, CancellationToken cancellationToken)
        {
            var curBuffCount = _sender.BufferItem(span);

            if (curBuffCount >= BatchSize)
            {
                return(await _sender.FlushAsync(_process, cancellationToken));
            }

            return(0);
        }
        public void TestConvertSpanOneReferenceChildOf()
        {
            Span parent = (Span)_tracer.BuildSpan("foo").Start();

            Span child = (Span)_tracer.BuildSpan("foo")
                         .AsChildOf(parent)
                         .Start();

            ThriftSpan span = JaegerThriftSpanConverter.ConvertSpan(child);

            Assert.Equal((long)child.Context.ParentId, span.ParentSpanId);
            Assert.Empty(span.References);
        }
        public void TestConvertSpanMixedReferences()
        {
            Span parent  = (Span)_tracer.BuildSpan("foo").Start();
            Span parent2 = (Span)_tracer.BuildSpan("foo").Start();

            Span child = (Span)_tracer.BuildSpan("foo")
                         .AddReference(References.FollowsFrom, parent.Context)
                         .AsChildOf(parent2)
                         .Start();

            ThriftSpan span = JaegerThriftSpanConverter.ConvertSpan(child);

            Assert.Equal(0, span.ParentSpanId);
            Assert.Equal(2, span.References.Count);
            Assert.Equal(BuildReference(parent.Context, References.FollowsFrom), span.References[0], _thriftReferenceComparer);
            Assert.Equal(BuildReference(parent2.Context, References.ChildOf), span.References[1], _thriftReferenceComparer);
        }
示例#10
0
        public async void Dispose_ShouldFlushAnyItemsCurrentlyInTheBuffer()
        {
            var sender = new TestingSender
            {
                SendAsyncDelegate = Substitute.For <Func <List <JaegerSpan>, CancellationToken, Task <int> > >()
            };
            var item = new JaegerSpan();

            sender.BufferItem(item);
            sender.BufferItem(item);
            sender.BufferItem(item);

            sender.Dispose();

            Assert.Empty(sender.Buffer);
            await sender.SendAsyncDelegate.Received(1)(Arg.Is <List <JaegerSpan> >(js => js.Count == 3), Arg.Any <CancellationToken>());
        }
示例#11
0
        public async Task <int> AppendAsync(Span span, CancellationToken cancellationToken)
        {
            if (_process == null)
            {
                _process          = new ThriftProcess(span.Tracer.ServiceName);
                _process.Tags     = JaegerThriftSpanConverter.BuildTags(span.Tracer.Tags);
                _processBytesSize = CalculateProcessSize(_process);
                _byteBufferSize  += _processBytesSize;
            }

            ThriftSpan thriftSpan = JaegerThriftSpanConverter.ConvertSpan(span);
            int        spanSize   = CalculateSpanSize(thriftSpan);

            if (spanSize > MaxSpanBytes)
            {
                throw new SenderException($"ThriftSender received a span that was too large, size = {spanSize}, max = {MaxSpanBytes}", null, 1);
            }

            _byteBufferSize += spanSize;
            if (_byteBufferSize <= MaxSpanBytes)
            {
                _spanBuffer.Add(thriftSpan);
                if (_byteBufferSize < MaxSpanBytes)
                {
                    return(0);
                }
                return(await FlushAsync(cancellationToken).ConfigureAwait(false));
            }

            int n;

            try
            {
                n = await FlushAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (SenderException ex)
            {
                // +1 for the span not submitted in the buffer above
                throw new SenderException(ex.Message, ex, ex.DroppedSpanCount + 1);
            }

            _spanBuffer.Add(thriftSpan);
            _byteBufferSize = _processBytesSize + spanSize;
            return(n);
        }
示例#12
0
        /// <inheritdoc />
        /// <summary>
        /// ProtocolAppendLogicAsync contains the specific logic for appending spans to be
        /// sent over UDP. It will keep track of the byte size of the information to be sent
        /// to the Jaeger Agent and make sure that it does not go over the max UDP packet size
        /// by automatically flushing the buffer. It will throw and exception if the span is
        /// too large to send in one UDP packet by itself.
        /// </summary>
        /// <param name="span">The span serialized in Jaeger Thrift</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal override async Task <int> ProtocolAppendLogicAsync(JaegerSpan span, CancellationToken cancellationToken)
        {
            if (_processByteSize == 0)
            {
                _processByteSize = await CalcSizeOfSerializedThrift(_process);

                _byteBufferSize += _processByteSize;
            }

            var spanSize = await CalcSizeOfSerializedThrift(span);

            if (spanSize > _maxByteBufferSize)
            {
                throw new Exception("Span too large to send over UDP");
            }

            _byteBufferSize += spanSize;

            // if the span fits in the buffer, buffer it
            if (_byteBufferSize <= _maxByteBufferSize)
            {
                _sender.BufferItem(span);

                // if we can potentially fit more spans in the buffer don't flush
                if (_byteBufferSize < _maxByteBufferSize)
                {
                    return(0);
                }

                // can't fit anything else in the buffer, flush it
                _byteBufferSize = _processByteSize;
                return(await FlushAsync(cancellationToken));
            }

            // the latest span did not fit in the buffer
            var sent = await FlushAsync(cancellationToken);

            _sender.BufferItem(span);
            _byteBufferSize = spanSize + _processByteSize;

            return(sent);
        }
        public void TestConvertSpan()
        {
            var logTimestamp = new DateTimeOffset(2018, 4, 13, 10, 30, 0, TimeSpan.Zero);
            var fields       = new Dictionary <string, object> {
                { "k", "v" }
            };

            Span span = (Span)_tracer.BuildSpan("operation-name").Start();

            span.Log(logTimestamp, fields);
            span.SetBaggageItem("foo", "bar");

            ThriftSpan thriftSpan = JaegerThriftSpanConverter.ConvertSpan(span);

            Assert.Equal("operation-name", thriftSpan.OperationName);
            Assert.Equal(2, thriftSpan.Logs.Count);
            ThriftLog thriftLog = thriftSpan.Logs[0];

            Assert.Equal(logTimestamp.ToUnixTimeMilliseconds() * 1000, thriftLog.Timestamp);
            Assert.Single(thriftLog.Fields);
            ThriftTag thriftTag = thriftLog.Fields[0];

            Assert.Equal("k", thriftTag.Key);
            Assert.Equal("v", thriftTag.VStr);

            // NOTE: In Java, the order is different (event, value, key) because the HashMap algorithm is different.
            thriftLog = thriftSpan.Logs[1];
            Assert.Equal(3, thriftLog.Fields.Count);
            thriftTag = thriftLog.Fields[0];
            Assert.Equal("event", thriftTag.Key);
            Assert.Equal("baggage", thriftTag.VStr);
            thriftTag = thriftLog.Fields[1];
            Assert.Equal("key", thriftTag.Key);
            Assert.Equal("foo", thriftTag.VStr);
            thriftTag = thriftLog.Fields[2];
            Assert.Equal("value", thriftTag.Key);
            Assert.Equal("bar", thriftTag.VStr);
        }
        public JaegerSpan BuildJaegerThriftSpan(ILetsTraceSpan span)
        {
            var context   = span.Context;
            var startTime = span.StartTimestamp.ToUnixTimeMicroseconds();
            var duration  = (span.FinishTimestamp?.ToUnixTimeMicroseconds() - startTime) ?? 0;

            var jaegerSpan = new JaegerSpan(
                (long)context.TraceId.Low,
                (long)context.TraceId.High,
                context.SpanId,
                context.ParentId,
                span.OperationName,
                0,
                startTime,
                duration
                )
            {
                Tags       = BuildJaegerTags(span.Tags),
                Logs       = span.Logs.Select(BuildJaegerLog).ToList(),
                References = span.References.Select(BuildJaegerReference).Where(r => r != null).ToList()
            };

            return(jaegerSpan);
        }
示例#15
0
        public async void FlushAsync_ShouldCallSendAsyncAndReturnCountOfSpansSent()
        {
            var sender = new TestingSender
            {
                SendAsyncDelegate = Substitute.For <Func <List <JaegerSpan>, CancellationToken, Task <int> > >()
            };
            var item    = new JaegerSpan();
            var process = new JaegerProcess("testingService");
            var cts     = new CancellationTokenSource();
            var token   = cts.Token;

            sender.BufferItem(item);
            sender.BufferItem(item);
            sender.BufferItem(item);
            sender.BufferItem(item);

            sender.SendAsyncDelegate(Arg.Is <List <JaegerSpan> >(js => js.Count == 4), Arg.Is(token)).Returns(4);

            var sent = await sender.FlushAsync(process, token);

            Assert.Equal(4, sent);
            Assert.Empty(sender.Buffer);
            await sender.SendAsyncDelegate.Received(1)(Arg.Is <List <JaegerSpan> >(js => js.Count == 4), Arg.Is(token));
        }
示例#16
0
 /// <summary>
 /// ProtocolAppendLogicAsync is the internal function to be implemented by concrete
 /// JaegerThriftTransport that handles the logic after AppendAsync serializes a span.
 /// When implementing ProtocolAppendLogicAsync it can be assumed that _process is populated.
 /// </summary>
 /// <param name="span">The span serialized in Jaeger Thrift</param>
 /// <param name="cancellationToken"></param>
 /// <returns></returns>
 internal abstract Task <int> ProtocolAppendLogicAsync(JaegerSpan span, CancellationToken cancellationToken);