Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into tests-out-of-repo-tar…
Browse files Browse the repository at this point in the history
…gets

# Conflicts:
#	tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj
  • Loading branch information
radical committed Jul 17, 2024
2 parents 994695a + 1f94dac commit a15b208
Show file tree
Hide file tree
Showing 38 changed files with 1,092 additions and 59 deletions.
9 changes: 8 additions & 1 deletion Aspire.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
Expand Down Expand Up @@ -514,6 +514,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Qdrant.Tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Kafka.Tests", "tests\Aspire.Hosting.Kafka.Tests\Aspire.Hosting.Kafka.Tests.csproj", "{0A83AA67-221E-44B4-9BA9-DC64DC17949E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Python.Tests", "tests\Aspire.Hosting.Python.Tests\Aspire.Hosting.Python.Tests.csproj", "{72F5A6F3-3516-402B-8F8D-50A7BC2E4BD4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Valkey.Tests", "tests\Aspire.Hosting.Valkey.Tests\Aspire.Hosting.Valkey.Tests.csproj", "{1C16DC2D-3B79-4081-AC1E-F3F965C61216}"
EndProject
Global
Expand Down Expand Up @@ -1334,6 +1336,10 @@ Global
{1BC02557-B78B-48CE-9D3C-488A6B7672F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BC02557-B78B-48CE-9D3C-488A6B7672F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BC02557-B78B-48CE-9D3C-488A6B7672F4}.Release|Any CPU.Build.0 = Release|Any CPU
{72F5A6F3-3516-402B-8F8D-50A7BC2E4BD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72F5A6F3-3516-402B-8F8D-50A7BC2E4BD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72F5A6F3-3516-402B-8F8D-50A7BC2E4BD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72F5A6F3-3516-402B-8F8D-50A7BC2E4BD4}.Release|Any CPU.Build.0 = Release|Any CPU
{7425E5B2-BC47-4521-AC40-B8CECA329E08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7425E5B2-BC47-4521-AC40-B8CECA329E08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7425E5B2-BC47-4521-AC40-B8CECA329E08}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -1593,6 +1599,7 @@ Global
{C424395C-1235-41A4-BF55-07880A04368C} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{830A89EC-4029-4753-B25A-068BAE37DEC7} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{1BC02557-B78B-48CE-9D3C-488A6B7672F4} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{72F5A6F3-3516-402B-8F8D-50A7BC2E4BD4} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{7425E5B2-BC47-4521-AC40-B8CECA329E08} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{8E2AA85E-C351-47B4-AF91-58557FAD5840} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{0A83AA67-221E-44B4-9BA9-DC64DC17949E} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
Expand Down
81 changes: 78 additions & 3 deletions playground/Stress/Stress.ApiService/TraceCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ public class TraceCreator

private static readonly ActivitySource s_activitySource = new(ActivitySourceName);

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

public async Task CreateTraceAsync(int count, bool createChildren)
{
for (var i = 0; i < count; i++)
var activityStack = new Stack<Activity>();

for (var i = 0; i < 10; i++)
{
if (i > 0)
{
Expand All @@ -27,19 +31,39 @@ public async Task CreateTraceAsync(int count, bool createChildren)
continue;
}

_allActivities.Add(activity);

if (createChildren)
{
await CreateChildActivityAsync(name);
}

await Task.Delay(Random.Shared.Next(10, 50));
}

while (activityStack.Count > 0)
{
activityStack.Pop().Stop();
}
}

private static async Task CreateChildActivityAsync(string parentName)
private async Task CreateChildActivityAsync(string parentName)
{
if (Random.Shared.NextDouble() > 0.05)
{
var name = parentName + "-0";
using var activity = s_activitySource.StartActivity(name, ActivityKind.Client);

var links = CreateLinks();

using var activity = s_activitySource.StartActivity(ActivityKind.Client, name: name, links: links.DistinctBy(l => l.Context.SpanId));
if (activity == null)
{
return;
}

AddEvents(activity);

_allActivities.Add(activity);

await Task.Delay(Random.Shared.Next(10, 50));

Expand All @@ -48,4 +72,55 @@ private static async Task CreateChildActivityAsync(string parentName)
await Task.Delay(Random.Shared.Next(10, 50));
}
}

private static void AddEvents(Activity activity)
{
var eventCount = Random.Shared.Next(0, 5);
for (var i = 0; i < eventCount; i++)
{
var activityTags = new ActivityTagsCollection();
var tagsCount = Random.Shared.Next(0, 3);
for (var j = 0; j < tagsCount; j++)
{
activityTags.Add($"key-{j}", "Value!");
}

activity.AddEvent(new ActivityEvent($"event-{i}", DateTimeOffset.UtcNow.AddMilliseconds(1), activityTags));
}
}

private ActivityLink[] CreateLinks()
{
var activityLinkCount = Random.Shared.Next(0, Math.Min(5, _allActivities.Count));
var links = new ActivityLink[activityLinkCount];
for (var i = 0; i < links.Length; i++)
{
// Randomly create some tags.
var activityTags = new ActivityTagsCollection();
var tagsCount = Random.Shared.Next(0, 3);
for (var j = 0; j < tagsCount; j++)
{
activityTags.Add($"key-{j}", "Value!");
}

// Create the activity link. There is a 50% chance the activity link goes to an activity
// that doesn't exist. This logic is here to ensure incomplete links are handled correctly.
ActivityContext activityContext;
if (Random.Shared.Next() % 2 == 0)
{
var a = _allActivities[Random.Shared.Next(0, _allActivities.Count)];
activityContext = a.Context;
}
else
{
activityContext = new ActivityContext(
ActivityTraceId.CreateRandom(),
ActivitySpanId.CreateRandom(),
ActivityTraceFlags.None);
}
links[i] = new ActivityLink(activityContext, activityTags);
}

return links;
}
}
7 changes: 1 addition & 6 deletions src/Aspire.Dashboard/Components/Controls/Chart/ChartBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ private void AddExemplars(List<ChartExemplar> exemplars, MetricValueBase metric)
var key = new SpanKey(exemplar.TraceId, exemplar.SpanId);
if (!_currentCache.TryGetValue(key, out var span))
{
span = GetSpan(exemplar.TraceId, exemplar.SpanId);
span = TelemetryRepository.GetSpan(exemplar.TraceId, exemplar.SpanId);
}
if (span != null)
{
Expand Down Expand Up @@ -505,11 +505,6 @@ private async Task UpdateChart(bool tickUpdate, DateTimeOffset inProgressDataTim
await OnChartUpdated(traces, xValues, exemplars, tickUpdate, inProgressDataTime);
}

protected OtlpSpan? GetSpan(string traceId, string spanId)
{
return MetricsHelpers.GetSpan(TelemetryRepository, traceId, spanId);
}

private DateTimeOffset GetCurrentDataTime()
{
return TimeProvider.GetUtcNow().Subtract(TimeSpan.FromSeconds(1)); // Compensate for delay in receiving metrics from services.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public ChartInterop(PlotlyChart plotlyChart)
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}

[JSInvokable]
Expand All @@ -207,7 +208,7 @@ public async Task ViewSpan(string traceId, string spanId)
var available = await MetricsHelpers.WaitForSpanToBeAvailableAsync(
traceId,
spanId,
_plotlyChart.GetSpan,
_plotlyChart.TelemetryRepository.GetSpan,
_plotlyChart.DialogService,
_plotlyChart.InvokeAsync,
_plotlyChart.DialogsLoc,
Expand Down
72 changes: 70 additions & 2 deletions src/Aspire.Dashboard/Components/Controls/SpanDetails.razor
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
@using Aspire.Dashboard.Model
@using Aspire.Dashboard.Model.Otlp
@using Aspire.Dashboard.Otlp.Model
@using Aspire.Dashboard.Resources
@using Aspire.Dashboard.Utils
@inject IStringLocalizer<ControlsStrings> Loc
@inject IStringLocalizer<Dialogs> DialogsLoc

<div class="span-details-layout">
<FluentToolbar Orientation="Orientation.Horizontal">
Expand Down Expand Up @@ -91,8 +93,6 @@
<ExtraValueContent>
@if (context.Attributes.Length > 0)
{
<div class="event-attributes-header">@Loc[nameof(ControlsStrings.TraceDetailAttributesHeader)]</div>

/* There's a weird bug where trying to render a nested FluentDataGrid here with a non-primitive
TItem leads to the click event not being raised *only in the value (not header) rows*. A
workaround is to use the attribute index as the item and query the attributes list for its
Expand All @@ -109,6 +109,74 @@
</ExtraValueContent>
</PropertyGrid>
</FluentAccordionItem>
<FluentAccordionItem Heading="@Loc[nameof(ControlsStrings.SpanDetailsLinksHeader)]" Expanded="true">
<div slot="end">
<FluentBadge Appearance="Appearance.Neutral" Circular="true">
@FilteredSpanLinks.Count()
</FluentBadge>
</div>
<FluentDataGrid TGridItem="SpanLinkViewModel"
Items="@FilteredSpanLinks"
Style="width:100%"
GenerateHeader="GenerateHeaderOption.Sticky"
GridTemplateColumns="4fr 1fr">
<TemplateColumn Title="@Loc[nameof(ControlsStrings.SpanDetailsSpanColumnHeader)]">
@WriteSpanLink(context)
</TemplateColumn>
<TemplateColumn Title="@Loc[nameof(ControlsStrings.SpanDetailsDetailsColumnHeader)]">
<FluentButton Appearance="Appearance.Lightweight" OnClick="@(() => OnViewDetailsAsync(context))">@Loc[nameof(ControlsStrings.ViewAction)]</FluentButton>
</TemplateColumn>
</FluentDataGrid>
</FluentAccordionItem>
<FluentAccordionItem Heading="@Loc[nameof(ControlsStrings.SpanDetailsBacklinksHeader)]" Expanded="true">
<div slot="end">
<FluentBadge Appearance="Appearance.Neutral" Circular="true">
@FilteredSpanBacklinks.Count()
</FluentBadge>
</div>
<FluentDataGrid TGridItem="SpanLinkViewModel"
Items="@FilteredSpanBacklinks"
Style="width:100%"
GenerateHeader="GenerateHeaderOption.Sticky"
GridTemplateColumns="4fr 1fr">
<TemplateColumn Title="@Loc[nameof(ControlsStrings.SpanDetailsSpanColumnHeader)]">
@WriteSpanLink(context)
</TemplateColumn>
<TemplateColumn Title="@Loc[nameof(ControlsStrings.SpanDetailsDetailsColumnHeader)]">
<FluentButton Appearance="Appearance.Lightweight" OnClick="@(() => OnViewDetailsAsync(context))">@Loc[nameof(ControlsStrings.ViewAction)]</FluentButton>
</TemplateColumn>
</FluentDataGrid>
</FluentAccordionItem>
</FluentAccordion>
</div>
</div>

@code {
RenderFragment WriteSpanLink(SpanLinkViewModel context)
{
var content = context.Span != null
? SpanWaterfallViewModel.GetTitle(context.Span, ViewModel.Applications)
: $"{Loc[nameof(ControlsStrings.SpanDetailsSpanPrefix)]}: {OtlpHelpers.ToShortenedId(context.SpanId)}";
var color = context.Span != null
? ColorGenerator.Instance.GetColorHexByKey(OtlpApplication.GetResourceName(context.Span.Source, ViewModel.Applications))
: "transparent";

return @<div>
<div class="spanlink-container" style="height:32px;">
<span class="spanlink-text" title="@content" style="padding-left:5px; border-left-width: 5px; border-left-style: solid; border-left-color: @(color);">
@content
</span>
</div>
@if (context.Attributes.Length > 0)
{
<PropertyGrid TItem="SpanPropertyViewModel"
Items="@Queryable.AsQueryable(context.Attributes.Select(a => new SpanPropertyViewModel() { Name = a.Key, Value = a.Value }))"
GridTemplateColumns="1fr 2fr"
NameColumnValue="(vm) => vm.Name"
ValueColumnValue="(vm) => vm.Value"
IsNameSortable="false"
IsValueSortable="false" />
}
</div>;
}
}
43 changes: 42 additions & 1 deletion src/Aspire.Dashboard/Components/Controls/SpanDetails.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,27 @@

using Aspire.Dashboard.Model;
using Aspire.Dashboard.Otlp.Model;
using Aspire.Dashboard.Otlp.Storage;
using Aspire.Dashboard.Utils;
using Microsoft.AspNetCore.Components;
using Microsoft.FluentUI.AspNetCore.Components;

namespace Aspire.Dashboard.Components.Controls;

public partial class SpanDetails
public partial class SpanDetails : IDisposable
{
[Parameter, EditorRequired]
public required SpanDetailsViewModel ViewModel { get; set; }

[Inject]
public required IDialogService DialogService { get; init; }

[Inject]
public required NavigationManager NavigationManager { get; init; }

[Inject]
public required TelemetryRepository TelemetryRepository { get; init; }

private IQueryable<SpanPropertyViewModel> FilteredItems =>
ViewModel.Properties.Where(ApplyFilter).AsQueryable();

Expand All @@ -27,8 +38,15 @@ public partial class SpanDetails
private IQueryable<OtlpSpanEvent> FilteredSpanEvents =>
ViewModel.Span.Events.Where(e => e.Name.Contains(_filter, StringComparison.CurrentCultureIgnoreCase)).OrderBy(e => e.Time).AsQueryable();

private IQueryable<SpanLinkViewModel> FilteredSpanLinks =>
ViewModel.Links.Where(e => e.SpanId.Contains(_filter, StringComparison.CurrentCultureIgnoreCase)).AsQueryable();

private IQueryable<SpanLinkViewModel> FilteredSpanBacklinks =>
ViewModel.Backlinks.Where(e => e.SpanId.Contains(_filter, StringComparison.CurrentCultureIgnoreCase)).AsQueryable();

private string _filter = "";
private List<KeyValuePair<string, string>> _contextAttributes = null!;
private readonly CancellationTokenSource _cts = new();

private readonly GridSort<SpanPropertyViewModel> _nameSort = GridSort<SpanPropertyViewModel>.ByAscending(vm => vm.Name);
private readonly GridSort<SpanPropertyViewModel> _valueSort = GridSort<SpanPropertyViewModel>.ByAscending(vm => vm.Value);
Expand Down Expand Up @@ -58,4 +76,27 @@ protected override void OnParametersSet()
_contextAttributes.Add(new KeyValuePair<string, string>("TraceId", ViewModel.Span.TraceId));
}
}

public async Task OnViewDetailsAsync(SpanLinkViewModel linkVM)
{
var available = await MetricsHelpers.WaitForSpanToBeAvailableAsync(
traceId: linkVM.TraceId,
spanId: linkVM.SpanId,
getSpan: TelemetryRepository.GetSpan,
DialogService,
InvokeAsync,
DialogsLoc,
_cts.Token).ConfigureAwait(false);

if (available)
{
NavigationManager.NavigateTo(DashboardUrls.TraceDetailUrl(linkVM.TraceId, spanId: linkVM.SpanId));
}
}

public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
}
13 changes: 10 additions & 3 deletions src/Aspire.Dashboard/Components/Controls/SpanDetails.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@
margin-bottom: 0;
}

::deep .event-attributes-header {
font-weight: bold;
margin: 5px 0;
::deep .spanlink-container {
display: grid;
grid-template-columns: 1fr auto;
gap: calc((6 + (var(--design-unit) * var(--density))) * 1px);
align-items: center;
}

::deep .spanlink-text {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task OnViewDetailsAsync(ChartExemplar exemplar)
var available = await MetricsHelpers.WaitForSpanToBeAvailableAsync(
traceId: exemplar.TraceId,
spanId: exemplar.SpanId,
getSpan: (traceId, spanId) => MetricsHelpers.GetSpan(TelemetryRepository, traceId, spanId),
getSpan: TelemetryRepository.GetSpan,
DialogService,
InvokeAsync,
Loc,
Expand Down Expand Up @@ -79,6 +79,7 @@ private string FormatMetricValue(double? value)

public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
}
Loading

0 comments on commit a15b208

Please sign in to comment.