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); }
public int BufferItem(JaegerSpan item) { lock (_buffer) { _buffer.Add(item); return(_buffer.Count); } }
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); }
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)); }
protected int CalculateSpanSize(ThriftSpan span) { try { return(GetSize(span)); } catch (Exception ex) { throw new SenderException("ThriftSender failed writing Span to memory buffer.", ex, 1); } }
/// <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); }
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>()); }
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); }
/// <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); }
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)); }
/// <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);