Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
43 changes: 43 additions & 0 deletions Lite/Controls/ServerTab.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,49 @@
</Grid>
</TabItem>

<!-- Collection Health Tab -->
<TabItem Header="Collection Health">
<Grid Margin="8">
<DataGrid x:Name="CollectionHealthGrid"
AutoGenerateColumns="False" IsReadOnly="True"
RowStyle="{StaticResource GridRowStyle}"
HeadersVisibility="Column" GridLinesVisibility="Horizontal">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding CollectorName}" Width="180">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="CollectorName" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Collector" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding HealthStatus}" Width="90">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="HealthStatus" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Status" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding TotalRuns, StringFormat=N0}" Width="80">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="TotalRuns" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Runs" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding SuccessCount, StringFormat=N0}" Width="80">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="SuccessCount" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Success" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding ErrorCount, StringFormat=N0}" Width="80">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="ErrorCount" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Errors" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding FailureRatePercent, StringFormat=N1}" Width="85">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="FailureRatePercent" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Fail %" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding AvgDurationFormatted}" Width="100">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="AvgDurationFormatted" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Avg Duration" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding LastSuccessFormatted}" Width="140">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="LastSuccessFormatted" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Last Success" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding LastRunFormatted}" Width="140">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="LastRunFormatted" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Last Run" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding LastError}" Width="*">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="LastError" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Last Error" FontWeight="Bold" VerticalAlignment="Center"/></StackPanel></DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</TabItem>

</TabControl>
</Grid>
</UserControl>
7 changes: 6 additions & 1 deletion Lite/Controls/ServerTab.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public partial class ServerTab : UserControl
private DataGridFilterManager<DatabaseConfigRow>? _databaseConfigFilterMgr;
private DataGridFilterManager<DatabaseScopedConfigRow>? _dbScopedConfigFilterMgr;
private DataGridFilterManager<TraceFlagRow>? _traceFlagsFilterMgr;
private DataGridFilterManager<CollectorHealthRow>? _collectionHealthFilterMgr;

private static readonly HashSet<string> _defaultPerfmonCounters = new(StringComparer.OrdinalIgnoreCase)
{
Expand Down Expand Up @@ -444,14 +445,15 @@ private async System.Threading.Tasks.Task RefreshAllDataAsync()
var databaseScopedConfigTask = SafeQueryAsync(() => _dataService.GetLatestDatabaseScopedConfigAsync(_serverId));
var traceFlagsTask = SafeQueryAsync(() => _dataService.GetLatestTraceFlagsAsync(_serverId));
var runningJobsTask = SafeQueryAsync(() => _dataService.GetRunningJobsAsync(_serverId));
var collectionHealthTask = SafeQueryAsync(() => _dataService.GetCollectionHealthAsync(_serverId));
/* Core data tasks */
await System.Threading.Tasks.Task.WhenAll(
snapshotsTask, cpuTask, memoryTask, memoryTrendTask,
queryStatsTask, procStatsTask, fileIoTask, fileIoTrendTask, tempDbTask, tempDbFileIoTask,
deadlockTask, blockedProcessTask, waitTypesTask, perfmonCountersTask,
queryStoreTask, memoryGrantTrendTask,
serverConfigTask, databaseConfigTask, databaseScopedConfigTask, traceFlagsTask,
runningJobsTask);
runningJobsTask, collectionHealthTask);

/* Trend chart tasks - run separately so failures don't kill the whole refresh */
var blockingTrendTask = SafeQueryAsync(() => _dataService.GetBlockingTrendAsync(_serverId, hoursBack, fromDate, toDate));
Expand Down Expand Up @@ -488,6 +490,7 @@ await System.Threading.Tasks.Task.WhenAll(
_dbScopedConfigFilterMgr!.UpdateData(databaseScopedConfigTask.Result);
_traceFlagsFilterMgr!.UpdateData(traceFlagsTask.Result);
_runningJobsFilterMgr!.UpdateData(runningJobsTask.Result);
_collectionHealthFilterMgr!.UpdateData(collectionHealthTask.Result);

/* Update memory summary */
UpdateMemorySummary(memoryTask.Result);
Expand Down Expand Up @@ -1864,6 +1867,7 @@ private void InitializeFilterManagers()
_databaseConfigFilterMgr = new DataGridFilterManager<DatabaseConfigRow>(DatabaseConfigGrid);
_dbScopedConfigFilterMgr = new DataGridFilterManager<DatabaseScopedConfigRow>(DatabaseScopedConfigGrid);
_traceFlagsFilterMgr = new DataGridFilterManager<TraceFlagRow>(TraceFlagsGrid);
_collectionHealthFilterMgr = new DataGridFilterManager<CollectorHealthRow>(CollectionHealthGrid);

_filterManagers[QuerySnapshotsGrid] = _querySnapshotsFilterMgr;
_filterManagers[QueryStatsGrid] = _queryStatsFilterMgr;
Expand All @@ -1876,6 +1880,7 @@ private void InitializeFilterManagers()
_filterManagers[DatabaseConfigGrid] = _databaseConfigFilterMgr;
_filterManagers[DatabaseScopedConfigGrid] = _dbScopedConfigFilterMgr;
_filterManagers[TraceFlagsGrid] = _traceFlagsFilterMgr;
_filterManagers[CollectionHealthGrid] = _collectionHealthFilterMgr;
}

private void EnsureFilterPopup()
Expand Down
8 changes: 8 additions & 0 deletions Lite/Services/LocalDataService.CollectionHealth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,13 @@ public string HealthStatus
public string AvgDurationFormatted => AvgDurationMs < 1000
? $"{AvgDurationMs:F0} ms"
: $"{AvgDurationMs / 1000:F1} s";

public string LastSuccessFormatted => LastSuccessTime.HasValue
? LastSuccessTime.Value.ToLocalTime().ToString("MM/dd HH:mm:ss")
: "Never";

public string LastRunFormatted => LastRunTime.HasValue
? LastRunTime.Value.ToLocalTime().ToString("MM/dd HH:mm:ss")
: "Never";
}