912 lines
38 KiB
C#
912 lines
38 KiB
C#
// <copyright file="SpanBuilderTest.cs" company="OpenTelemetry Authors">
|
|
// Copyright 2018, OpenTelemetry Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// </copyright>
|
|
|
|
namespace OpenTelemetry.Trace.Test
|
|
{
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenTelemetry.Abstractions.Utils;
|
|
using OpenTelemetry.Context.Propagation;
|
|
using OpenTelemetry.Trace.Configuration;
|
|
using OpenTelemetry.Trace.Export;
|
|
using OpenTelemetry.Trace.Sampler;
|
|
using OpenTelemetry.Resources;
|
|
using Xunit;
|
|
|
|
public class SpanBuilderTest : IDisposable
|
|
{
|
|
private static readonly string SpanName = "MySpanName";
|
|
|
|
private readonly TracerConfiguration alwaysSampleTracerConfiguration = new TracerConfiguration(Samplers.AlwaysSample);
|
|
|
|
private readonly SpanProcessor spanProcessor = new SimpleSpanProcessor(new NoopSpanExporter());
|
|
|
|
private readonly ITracer tracer;
|
|
public SpanBuilderTest()
|
|
{
|
|
tracer = new Tracer(spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanNullParent()
|
|
{
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.True(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
var spanData = ((Span)span);
|
|
Assert.True(spanData.ParentSpanId == default);
|
|
Assert.InRange(spanData.StartTimestamp, PreciseTimestamp.GetUtcNow().AddSeconds(-1), PreciseTimestamp.GetUtcNow().AddSeconds(1));
|
|
Assert.Equal(SpanName, spanData.Name);
|
|
|
|
var activity = ((Span)span).Activity;
|
|
Assert.Null(Activity.Current);
|
|
Assert.Equal(activity.TraceId, span.Context.TraceId);
|
|
Assert.Equal(activity.SpanId, span.Context.SpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanLastParentWins1()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
|
|
var span = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetNoParent()
|
|
.SetParent(spanContext)
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.Equal(spanContext.TraceId, span.Context.TraceId);
|
|
Assert.Equal(spanContext.SpanId, span.ParentSpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanLastParentWins2()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
|
|
var span = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetParent(spanContext)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.NotEqual(spanContext.TraceId, span.Context.TraceId);
|
|
Assert.True(span.ParentSpanId == default);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanLastParentWins3()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
var rootSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.StartSpan();
|
|
|
|
var childSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetParent(spanContext)
|
|
.SetParent(rootSpan)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(rootSpan.Context.SpanId, childSpan.ParentSpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanLastParentWins4()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
var rootSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.StartSpan();
|
|
|
|
var childSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetParent(rootSpan)
|
|
.SetParent(spanContext)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(spanContext.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(spanContext.SpanId, childSpan.ParentSpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanLastParentWins5()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
var activity = new Activity("foo")
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
|
|
var childSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetParent(spanContext)
|
|
.SetParent(activity)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(activity.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(activity.SpanId, childSpan.ParentSpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanLastParentWins6()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
var activity = new Activity("foo")
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
|
|
var childSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetParent(spanContext)
|
|
.SetCreateChild(false)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(activity.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(activity.SpanId, childSpan.Context.SpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanLastParentWins7()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
var activity = new Activity("foo")
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
|
|
var childSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetCreateChild(false)
|
|
.SetParent(spanContext)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(spanContext.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(spanContext.SpanId, childSpan.ParentSpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanNullParentWithRecordEvents()
|
|
{
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.NeverSample)
|
|
.SetRecordEvents(true)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.True(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
Assert.True(span.ParentSpanId == default);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanWithStartTimestamp()
|
|
{
|
|
var timestamp = DateTime.UtcNow.AddSeconds(-100);
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.AlwaysSample)
|
|
.SetStartTimestamp(timestamp)
|
|
.StartSpan();
|
|
|
|
Assert.Equal(timestamp, span.StartTimestamp);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanWithImplicitTimestamp()
|
|
{
|
|
var timestamp = PreciseTimestamp.GetUtcNow();
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.AlwaysSample)
|
|
.StartSpan();
|
|
|
|
Assert.InRange(Math.Abs((timestamp - span.StartTimestamp).TotalMilliseconds), 0, 20);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanNullParentNoRecordOptions()
|
|
{
|
|
var span = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.NeverSample)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.False(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartChildSpan()
|
|
{
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(rootSpan.Context.IsValid);
|
|
Assert.True(rootSpan.IsRecordingEvents);
|
|
Assert.True((rootSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
|
|
var childSpan = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(rootSpan)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(rootSpan.Context.SpanId, childSpan.ParentSpanId);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanInScopeOfCurrentActivity()
|
|
{
|
|
var parentActivity = new Activity(SpanName)
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
parentActivity.TraceStateString = "k1=v1,k2=v2";
|
|
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(parentActivity.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(parentActivity.SpanId, ((Span)childSpan).ParentSpanId);
|
|
|
|
var activity = ((Span)childSpan).Activity;
|
|
Assert.Equal(parentActivity, Activity.Current);
|
|
Assert.Equal(activity.Parent, parentActivity);
|
|
|
|
Assert.Equal("k1=v1,k2=v2", Abstractions.Context.Propagation.TracestateUtils.GetString(childSpan.Context.Tracestate));
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanInScopeOfCurrentActivityRecorded()
|
|
{
|
|
var parentActivity = new Activity(SpanName)
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
parentActivity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
|
|
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(parentActivity.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(parentActivity.SpanId, ((Span)childSpan).ParentSpanId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
parentActivity.Stop();
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanInScopeOfCurrentActivityNoParent()
|
|
{
|
|
var parentActivity = new Activity(SpanName).Start();
|
|
parentActivity.TraceStateString = "k1=v1,k2=v2";
|
|
|
|
var childSpan = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.NotEqual(parentActivity.TraceId, childSpan.Context.TraceId);
|
|
Assert.True(childSpan.ParentSpanId == default);
|
|
|
|
var activity = ((Span)childSpan).Activity;
|
|
Assert.Equal(parentActivity, Activity.Current);
|
|
Assert.Null(activity.Parent);
|
|
Assert.Equal(activity.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(activity.SpanId, childSpan.Context.SpanId);
|
|
Assert.Empty(childSpan.Context.Tracestate);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanFromExplicitActivity()
|
|
{
|
|
var parentActivity = new Activity(SpanName)
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
parentActivity.TraceStateString = "k1=v1,k2=v2";
|
|
parentActivity.Stop();
|
|
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(parentActivity)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(parentActivity.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(parentActivity.SpanId, ((Span)childSpan).ParentSpanId);
|
|
|
|
var activity = ((Span)childSpan).Activity;
|
|
Assert.NotNull(activity);
|
|
Assert.Null(Activity.Current);
|
|
Assert.Equal(activity.TraceId, parentActivity.TraceId);
|
|
Assert.Equal(activity.ParentSpanId, parentActivity.SpanId);
|
|
Assert.Equal(activity.SpanId, childSpan.Context.SpanId);
|
|
Assert.Equal("k1=v1,k2=v2", TracestateUtils.GetString(childSpan.Context.Tracestate));
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanFromExplicitRecordedActivity()
|
|
{
|
|
var parentActivity = new Activity(SpanName)
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
parentActivity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
|
|
parentActivity.Stop();
|
|
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(parentActivity)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(parentActivity.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(parentActivity.SpanId, ((Span)childSpan).ParentSpanId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanFromCurrentActivity()
|
|
{
|
|
var activity = new Activity(SpanName)
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
activity.TraceStateString = "k1=v1,k2=v2";
|
|
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetCreateChild(false)
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.Equal(activity.TraceId, span.Context.TraceId);
|
|
Assert.Equal(activity.SpanId, span.Context.SpanId);
|
|
Assert.True(((Span)span).ParentSpanId == default);
|
|
|
|
Assert.NotNull(Activity.Current);
|
|
Assert.Equal(Activity.Current, activity);
|
|
Assert.Equal("k1=v1,k2=v2", TracestateUtils.GetString(span.Context.Tracestate));
|
|
|
|
Assert.Equal(activity.StartTimeUtc, span.StartTimestamp);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanFromCurrentRecordedActivity()
|
|
{
|
|
var activity = new Activity(SpanName)
|
|
.SetIdFormat(ActivityIdFormat.W3C)
|
|
.Start();
|
|
activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded;
|
|
|
|
var span = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetCreateChild(false)
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.Equal(activity.TraceId, span.Context.TraceId);
|
|
Assert.Equal(activity.SpanId, span.Context.SpanId);
|
|
Assert.True(((Span)span).ParentSpanId == default);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
activity.Stop();
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_ExplicitNoParent()
|
|
{
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.True(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
|
|
Assert.True(span.ParentSpanId == default);
|
|
|
|
var activity = ((Span)span).Activity;
|
|
Assert.Null(Activity.Current);
|
|
Assert.Equal(activity.TraceId, span.Context.TraceId);
|
|
Assert.Equal(activity.SpanId, span.Context.SpanId);
|
|
Assert.Empty(span.Context.Tracestate);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_NoParent()
|
|
{
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.True(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
Assert.True(span.ParentSpanId == default);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_BlankSpanParent()
|
|
{
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(BlankSpan.Instance)
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.True(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
Assert.True(span.ParentSpanId == default);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_BlankSpanContextParent()
|
|
{
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(SpanContext.Blank)
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.True(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
|
|
Assert.True(span.ParentSpanId == default);
|
|
}
|
|
|
|
|
|
[Fact]
|
|
public void StartSpan_CurrentSpanParent()
|
|
{
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetParent(
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None,
|
|
new List<KeyValuePair<string, string>>{ new KeyValuePair<string, string>("k1", "v1") }))
|
|
.StartSpan();
|
|
using (tracer.WithSpan(rootSpan))
|
|
{
|
|
var childSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.Equal(rootSpan.Context.SpanId, childSpan.ParentSpanId);
|
|
Assert.Equal("k1=v1", TracestateUtils.GetString(childSpan.Context.Tracestate));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_NoParentInScopeOfCurrentSpan()
|
|
{
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.StartSpan();
|
|
using (tracer.WithSpan(rootSpan))
|
|
{
|
|
var childSpan = (Span)new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.NotEqual(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.True(childSpan.ParentSpanId == default);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpanInvalidParent()
|
|
{
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(SpanContext.Blank)
|
|
.StartSpan();
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.True(span.IsRecordingEvents);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
|
|
Assert.True(span.ParentSpanId == default);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartRemoteSpan()
|
|
{
|
|
var spanContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None,
|
|
new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("k1", "v1") });
|
|
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(spanContext)
|
|
.SetRecordEvents(true)
|
|
.StartSpan();
|
|
|
|
Assert.True(span.Context.IsValid);
|
|
Assert.Equal(spanContext.TraceId, span.Context.TraceId);
|
|
Assert.True((span.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
|
|
Assert.Equal(spanContext.SpanId, span.ParentSpanId);
|
|
Assert.Equal("k1=v1", TracestateUtils.GetString(span.Context.Tracestate));
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_WithLink()
|
|
{
|
|
var link = new Link(
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None));
|
|
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.AddLink(link)
|
|
.StartSpan();
|
|
|
|
var links = span.Links.ToArray();
|
|
|
|
Assert.Single(links);
|
|
|
|
Assert.Equal(link.Context.TraceId, links[0].Context.TraceId);
|
|
Assert.Equal(link.Context.SpanId, links[0].Context.SpanId);
|
|
Assert.Equal(link.Context.TraceOptions, links[0].Context.TraceOptions);
|
|
Assert.Equal(link.Context.Tracestate, links[0].Context.Tracestate);
|
|
Assert.Equal(0, links[0].Attributes.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_WithLinkFromActivity()
|
|
{
|
|
var contextLink = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.AddLink(contextLink)
|
|
.StartSpan();
|
|
|
|
var links = span.Links.ToArray();
|
|
|
|
Assert.Single(links);
|
|
|
|
Assert.NotEqual(default, contextLink.TraceId);
|
|
Assert.NotEqual(default, contextLink.SpanId);
|
|
Assert.Equal(contextLink.TraceId, links[0].Context.TraceId);
|
|
Assert.Equal(contextLink.SpanId, links[0].Context.SpanId);
|
|
Assert.Equal(contextLink.TraceOptions, links[0].Context.TraceOptions);
|
|
Assert.Empty(links[0].Context.Tracestate);
|
|
Assert.Equal(0, links[0].Attributes.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_WithLinkFromSpanContextAndAttributes()
|
|
{
|
|
var linkContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.AddLink(linkContext, new Dictionary<string, object> { ["k"] = "v", })
|
|
.StartSpan();
|
|
|
|
var links = span.Links.ToArray();
|
|
|
|
Assert.Single(links);
|
|
|
|
Assert.Equal(linkContext.TraceId, links[0].Context.TraceId);
|
|
Assert.Equal(linkContext.SpanId, links[0].Context.SpanId);
|
|
Assert.Equal(linkContext.TraceOptions, links[0].Context.TraceOptions);
|
|
Assert.Equal(linkContext.Tracestate, links[0].Context.Tracestate);
|
|
Assert.Equal(1, links[0].Attributes.Count);
|
|
Assert.True(links[0].Attributes.ContainsKey("k"));
|
|
Assert.Equal("v", links[0].Attributes["k"].ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public void StartSpan_WithLinkFromSpanContext()
|
|
{
|
|
var linkContext =
|
|
new SpanContext(
|
|
ActivityTraceId.CreateRandom(),
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None);
|
|
|
|
var span = (Span) new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.AddLink(linkContext)
|
|
.StartSpan();
|
|
|
|
var links = span.Links.ToArray();
|
|
|
|
Assert.Single(links);
|
|
|
|
Assert.Equal(linkContext.TraceId, links[0].Context.TraceId);
|
|
Assert.Equal(linkContext.SpanId, links[0].Context.SpanId);
|
|
Assert.Equal(linkContext.TraceOptions, links[0].Context.TraceOptions);
|
|
Assert.Equal(linkContext.Tracestate, links[0].Context.Tracestate);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartRootSpan_WithSpecifiedSampler()
|
|
{
|
|
// Apply given sampler before default sampler for root spans.
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetNoParent()
|
|
.SetSampler(Samplers.NeverSample)
|
|
.StartSpan();
|
|
|
|
Assert.True(rootSpan.Context.IsValid);
|
|
Assert.True((rootSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartRootSpan_WithoutSpecifiedSampler()
|
|
{
|
|
// Apply default sampler (always true in the tests) for root spans.
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(rootSpan.Context.IsValid);
|
|
Assert.True((rootSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartRemoteChildSpan_WithSpecifiedSampler()
|
|
{
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.AlwaysSample)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(rootSpan.Context.IsValid);
|
|
Assert.True((rootSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
// Apply given sampler before default sampler for spans with remote parent.
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.NeverSample)
|
|
.SetParent(rootSpan.Context)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartRemoteChildSpan_WithoutSpecifiedSampler()
|
|
{
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.NeverSample)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(rootSpan.Context.IsValid);
|
|
Assert.True((rootSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
// Apply default sampler (always true in the tests) for spans with remote parent.
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(rootSpan.Context)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartChildSpan_WithSpecifiedSampler()
|
|
{
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.AlwaysSample)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(rootSpan.Context.IsValid);
|
|
Assert.True((rootSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
// Apply the given sampler for child spans.
|
|
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.NeverSample)
|
|
.SetParent(rootSpan)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartChildSpan_WithoutSpecifiedSampler()
|
|
{
|
|
var rootSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.NeverSample)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True(rootSpan.Context.IsValid);
|
|
Assert.True((rootSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
|
|
// Don't apply the default sampler (always true) for child spans.
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(rootSpan)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpan.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartChildSpan_SampledLinkedParent()
|
|
{
|
|
var rootSpanUnsampled = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.NeverSample)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True((rootSpanUnsampled.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
var rootSpanSampled =
|
|
new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetSampler(Samplers.AlwaysSample)
|
|
.SetNoParent()
|
|
.StartSpan();
|
|
|
|
Assert.True((rootSpanSampled.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
// Sampled because the linked parent is sampled.
|
|
var childSpan = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.AddLink(new Link(rootSpanSampled.Context))
|
|
.SetParent(rootSpanUnsampled)
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(rootSpanUnsampled.Context.TraceId, childSpan.Context.TraceId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartRemoteChildSpan_WithProbabilitySamplerDefaultSampler()
|
|
{
|
|
// This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long
|
|
// is not less than probability * Long.MAX_VALUE;
|
|
var traceId =
|
|
ActivityTraceId.CreateFromBytes(
|
|
new byte[] {0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0,});
|
|
|
|
// If parent is sampled then the remote child must be sampled.
|
|
var childSpan =
|
|
new SpanBuilder(SpanName, spanProcessor, new TracerConfiguration(ProbabilitySampler.Create(0.1)), Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(new SpanContext(
|
|
traceId,
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.Recorded))
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(traceId, childSpan.Context.TraceId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0);
|
|
childSpan.End();
|
|
|
|
// If parent is not sampled then the remote child must be not sampled.
|
|
childSpan =
|
|
new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty)
|
|
.SetSpanKind(SpanKind.Internal)
|
|
.SetParent(new SpanContext(
|
|
traceId,
|
|
ActivitySpanId.CreateRandom(),
|
|
ActivityTraceFlags.None))
|
|
.StartSpan();
|
|
|
|
Assert.True(childSpan.Context.IsValid);
|
|
Assert.Equal(traceId, childSpan.Context.TraceId);
|
|
Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0);
|
|
childSpan.End();
|
|
}
|
|
|
|
[Fact]
|
|
public void SpanBuilder_BadArguments()
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() => new SpanBuilder(null, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty));
|
|
Assert.Throws<ArgumentNullException>(() => new SpanBuilder(SpanName, null, alwaysSampleTracerConfiguration, Resource.Empty));
|
|
Assert.Throws<ArgumentNullException>(() => new SpanBuilder(SpanName, spanProcessor, null, Resource.Empty));
|
|
|
|
var spanBuilder = new SpanBuilder(SpanName, spanProcessor, alwaysSampleTracerConfiguration, Resource.Empty);
|
|
Assert.Throws<ArgumentNullException>(() => spanBuilder.SetParent((ISpan)null));
|
|
Assert.Throws<ArgumentNullException>(() => spanBuilder.SetParent((SpanContext)null));
|
|
Assert.Throws<ArgumentNullException>(() => spanBuilder.SetParent((Activity)null));
|
|
|
|
// no Activity.Current
|
|
Assert.Throws<ArgumentException>(() => spanBuilder.SetCreateChild(false));
|
|
|
|
// Activity.Current wrong format
|
|
var a = new Activity("foo")
|
|
.SetIdFormat(ActivityIdFormat.Hierarchical)
|
|
.Start();
|
|
Assert.Throws<ArgumentException>(() => spanBuilder.SetCreateChild(false));
|
|
a.Stop();
|
|
|
|
Assert.Throws<ArgumentNullException>(() => spanBuilder.SetSampler(null));
|
|
Assert.Throws<ArgumentNullException>(() => spanBuilder.AddLink((Link)null));
|
|
Assert.Throws<ArgumentNullException>(() => spanBuilder.AddLink((SpanContext)null));
|
|
Assert.Throws<ArgumentNullException>(() => spanBuilder.AddLink(null, null));
|
|
Assert.Throws<ArgumentException>(() => spanBuilder.AddLink(SpanContext.Blank));
|
|
Assert.Throws<ArgumentException>(() => spanBuilder.AddLink(SpanContext.Blank, null));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Activity.Current = null;
|
|
}
|
|
}
|
|
}
|