Skip to content

Commit

Permalink
[release/9.0] Reject duplicate span ids (#6471)
Browse files Browse the repository at this point in the history
* [release/9.0] Reject duplicate span ids

* WIP

* Update
  • Loading branch information
JamesNK authored Oct 24, 2024
1 parent b1e81d7 commit 23bfd12
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 0 deletions.
15 changes: 15 additions & 0 deletions playground/Stress/Stress.ApiService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,19 @@ async IAsyncEnumerable<string> WriteOutput()
return "Log with formatted data";
});

app.MapGet("/duplicate-spanid", async () =>
{
var traceCreator = new TraceCreator();
var span1 = traceCreator.CreateActivity("Test 1", "0485b1947fe788bb");
await Task.Delay(1000);
span1?.Stop();
var span2 = traceCreator.CreateActivity("Test 2", "0485b1947fe788bb");
await Task.Delay(1000);
span2?.Stop();
return $"Created duplicate span IDs.";
});

app.Run();
17 changes: 17 additions & 0 deletions playground/Stress/Stress.ApiService/TraceCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Reflection;

namespace Stress.ApiService;

Expand All @@ -13,6 +14,22 @@ public class TraceCreator

private readonly List<Activity> _allActivities = new List<Activity>();

public Activity? CreateActivity(string name, string? spandId)
{
var activity = s_activitySource.StartActivity(name, ActivityKind.Client);
if (activity != null)
{
if (spandId != null)
{
// Gross but it's the only way.
typeof(Activity).GetField("_spanId", BindingFlags.Instance | BindingFlags.NonPublic)!.SetValue(activity, spandId);
typeof(Activity).GetField("_traceId", BindingFlags.Instance | BindingFlags.NonPublic)!.SetValue(activity, activity.TraceId.ToString());
}
}

return activity;
}

public async Task CreateTraceAsync(int count, bool createChildren)
{
var activityStack = new Stack<Activity>();
Expand Down
5 changes: 5 additions & 0 deletions src/Aspire.Dashboard/Otlp/Model/OtlpTrace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public int CalculateDepth(OtlpSpan span)

public void AddSpan(OtlpSpan span)
{
if (Spans.Any(s => s.SpanId == span.SpanId))
{
throw new InvalidOperationException($"Duplicate span id '{span.SpanId}' detected.");
}

var added = false;
for (var i = Spans.Count - 1; i >= 0; i--)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,57 @@ public void AddTraces()
});
}

[Fact]
public void AddTraces_DuplicateTraceIds_Reject()
{
// Arrange
var repository = CreateRepository();
// Act
var addContext = new AddContext();
repository.AddTraces(addContext, new RepeatedField<ResourceSpans>()
{
new ResourceSpans
{
Resource = CreateResource(),
ScopeSpans =
{
new ScopeSpans
{
Scope = CreateScope(),
Spans =
{
CreateSpan(traceId: "1", spanId: "1-1", startTime: s_testTime.AddMinutes(1), endTime: s_testTime.AddMinutes(10)),
CreateSpan(traceId: "1", spanId: "1-1", startTime: s_testTime.AddMinutes(5), endTime: s_testTime.AddMinutes(10)),
CreateSpan(traceId: "1", spanId: "1-2", startTime: s_testTime.AddMinutes(1), endTime: s_testTime.AddMinutes(10), parentSpanId: "1-1"),
}
}
}
}
});
// Assert
Assert.Equal(1, addContext.FailureCount);
var applications = repository.GetApplications();
Assert.Collection(applications,
app =>
{
Assert.Equal("TestService", app.ApplicationName);
Assert.Equal("TestId", app.InstanceId);
});
var traces = repository.GetTraces(new GetTracesRequest
{
ApplicationKey = applications[0].ApplicationKey,
FilterText = string.Empty,
StartIndex = 0,
Count = 10,
Filters = []
});
Assert.Collection(traces.PagedResult.Items,
trace =>
{
Assert.Equal(2, trace.Spans.Count);
});
}

[Fact]
public void AddTraces_Scope_Multiple()
{
Expand Down

0 comments on commit 23bfd12

Please sign in to comment.