Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ private void UpdateSpanActionsMenu()
}
});

if (GenAIHelpers.IsGenAISpan(ViewModel.Span.Attributes))
if (GenAIHelpers.HasGenAIAttribute(ViewModel.Span.Attributes))
{
_spanActionsMenuItems.Add(new MenuButtonItem
{
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
</AspireTemplateColumn>
<AspireTemplateColumn ColumnId="@MessageColumn" ColumnManager="@_manager" Title="@Loc[nameof(Dashboard.Resources.StructuredLogs.StructuredLogsMessageColumnHeader)]">
@* Tooltip is displayed by the message GridValue instance *@
<LogMessageColumnDisplay FilterText="@(ViewModel.FilterText)" LogEntry="@context" LaunchGenAIVisualizerCallback="@LaunchGenAIVisualizerAsync" />
<LogMessageColumnDisplay FilterText="@(ViewModel.FilterText)" LogEntry="@context" IsGenAILogCallback="@IsGenAILogEntry" LaunchGenAIVisualizerCallback="@LaunchGenAIVisualizerAsync" />
</AspireTemplateColumn>
<AspireTemplateColumn ColumnId="@TraceColumn" ColumnManager="@_manager" Title="@Loc[nameof(Dashboard.Resources.StructuredLogs.StructuredLogsTraceColumnHeader)]">
@if (!string.IsNullOrEmpty(context.TraceId))
Expand Down
56 changes: 51 additions & 5 deletions src/Aspire.Dashboard/Components/Pages/StructuredLogs.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,34 @@ public async Task UpdateViewModelFromQueryAsync(StructuredLogsPageViewModel view
await InvokeAsync(_dataGrid.SafeRefreshDataAsync);
}

private bool IsGenAILogEntry(OtlpLogEntry logEntry)
{
if (string.IsNullOrEmpty(logEntry.SpanId) || string.IsNullOrEmpty(logEntry.TraceId))
{
return false;
}

if (GenAIHelpers.HasGenAIAttribute(logEntry.Attributes))
{
// GenAI telemetry is on the log entry.
return true;
}

var span = TelemetryRepository.GetSpan(logEntry.TraceId, logEntry.SpanId);
if (span == null)
{
return false;
}

if (GenAIHelpers.HasGenAIAttribute(span.Attributes))
{
// Log entry belongs to a span that has GenAI telemetry.
return true;
}

return false;
}

private async Task LaunchGenAIVisualizerAsync(OtlpLogEntry logEntry)
{
var available = await TraceLinkHelpers.WaitForSpanToBeAvailableAsync(
Expand Down Expand Up @@ -571,7 +599,13 @@ await GenAIVisualizerDialog.OpenDialogAsync(
var filters = ViewModel.GetFilters();
filters.Add(new FieldTelemetryFilter
{
Field = GenAIHelpers.GenAISystem,
Field = KnownStructuredLogFields.SpanIdField,
Condition = FilterCondition.NotEqual,
Value = string.Empty
});
filters.Add(new FieldTelemetryFilter
{
Field = KnownStructuredLogFields.TraceIdField,
Condition = FilterCondition.NotEqual,
Value = string.Empty
});
Expand All @@ -584,10 +618,22 @@ await GenAIVisualizerDialog.OpenDialogAsync(
Filters = filters
});

return logs.Items
.DistinctBy(l => (l.SpanId, l.TraceId))
.Select(l => TelemetryRepository.GetSpan(l.TraceId, l.SpanId)!)
.ToList();
var genAISpans = new List<OtlpSpan>();
foreach (var l in logs.Items.DistinctBy(l => (l.SpanId, l.TraceId)))
{
var span = TelemetryRepository.GetSpan(l.TraceId, l.SpanId);
if (span == null)
{
continue;
}

if (GenAIHelpers.HasGenAIAttribute(l.Attributes) || GenAIHelpers.HasGenAIAttribute(span.Attributes))
{
genAISpans.Add(span);
}
}

return genAISpans;
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ private async Task ToggleSpanLogsAsync(OtlpLogEntry logEntry)

private static bool IsGenAISpan(SpanWaterfallViewModel spanViewModel)
{
return GenAIHelpers.IsGenAISpan(spanViewModel.Span.Attributes);
return GenAIHelpers.HasGenAIAttribute(spanViewModel.Span.Attributes);
}

private async Task OnGenAIClickedAsync(OtlpSpan span)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
HighlightText="@FilterText"
StopClickPropagation="true">
<ContentInButtonArea>
@if (!string.IsNullOrEmpty(LogEntry.TraceId) &&
!string.IsNullOrEmpty(LogEntry.SpanId) &&
GenAIHelpers.IsGenAISpan(LogEntry.Attributes))
@if (IsGenAILogCallback(LogEntry))
{
<FluentButton Appearance="Appearance.Lightweight"
Title="@ControlStringsLoc[nameof(ControlsStrings.GenAIDetailsTitle)]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public partial class LogMessageColumnDisplay
[Parameter, EditorRequired]
public required EventCallback<OtlpLogEntry> LaunchGenAIVisualizerCallback { get; set; }

[Parameter, EditorRequired]
public required Func<OtlpLogEntry, bool> IsGenAILogCallback { get; set; }

private string? _exceptionText;

protected override void OnInitialized()
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Model/GenAI/GenAIHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static class GenAIHelpers

public const string ErrorType = "error.type";

public static bool IsGenAISpan(KeyValuePair<string, string>[] attributes)
public static bool HasGenAIAttribute(KeyValuePair<string, string>[] attributes)
{
return attributes.GetValueWithFallback(GenAISystem, GenAIProviderName) is { Length: > 0 };
}
Expand Down
Loading