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
3 changes: 3 additions & 0 deletions Lite/Controls/ServerTab.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,9 @@
<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 LastErrorFormatted}" Width="140">
<DataGridTextColumn.Header><StackPanel Orientation="Horizontal"><Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="LastErrorFormatted" Click="FilterButton_Click" Margin="0,0,4,0"/><TextBlock Text="Last Error At" 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>
Expand Down
11 changes: 9 additions & 2 deletions Lite/Services/LocalDataService.CollectionHealth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public async Task<List<CollectorHealthRow>> GetCollectionHealthAsync(int serverI
AVG(duration_ms) AS avg_duration_ms,
MAX(CASE WHEN status = 'SUCCESS' THEN collection_time END) AS last_success_time,
MAX(collection_time) AS last_run_time,
MAX(CASE WHEN status = 'ERROR' THEN error_message END) AS last_error
MAX(CASE WHEN status = 'ERROR' THEN error_message END) AS last_error,
MAX(CASE WHEN status = 'ERROR' THEN collection_time END) AS last_error_time
FROM collection_log
WHERE server_id = $1
AND collection_time >= $2
Expand All @@ -54,7 +55,8 @@ GROUP BY collector_name
AvgDurationMs = reader.IsDBNull(4) ? 0 : ToDouble(reader.GetValue(4)),
LastSuccessTime = reader.IsDBNull(5) ? null : reader.GetDateTime(5),
LastRunTime = reader.IsDBNull(6) ? null : reader.GetDateTime(6),
LastError = reader.IsDBNull(7) ? null : reader.GetString(7)
LastError = reader.IsDBNull(7) ? null : reader.GetString(7),
LastErrorTime = reader.IsDBNull(8) ? null : reader.GetDateTime(8)
});
}

Expand Down Expand Up @@ -141,6 +143,7 @@ public class CollectorHealthRow
public DateTime? LastSuccessTime { get; set; }
public DateTime? LastRunTime { get; set; }
public string? LastError { get; set; }
public DateTime? LastErrorTime { get; set; }

public double FailureRatePercent => TotalRuns > 0 ? (double)ErrorCount / TotalRuns * 100 : 0;
public double HoursSinceLastSuccess => LastSuccessTime.HasValue
Expand Down Expand Up @@ -170,5 +173,9 @@ public string HealthStatus
public string LastRunFormatted => LastRunTime.HasValue
? LastRunTime.Value.ToLocalTime().ToString("MM/dd HH:mm:ss")
: "Never";

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

2 changes: 1 addition & 1 deletion Lite/Services/RemoteCollectorService.MemoryGrants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ WHERE mg.session_id <> @@SPID
reader.IsDBNull(9) ? 0L : Convert.ToInt64(reader.GetValue(9)),
reader.IsDBNull(10) ? false : Convert.ToBoolean(reader.GetValue(10)),
reader.IsDBNull(11) ? 0 : Convert.ToInt32(reader.GetValue(11)),
reader.IsDBNull(12) ? 0m : Convert.ToDecimal(reader.GetValue(12))));
reader.IsDBNull(12) ? 0m : SafeToDecimal(reader.GetValue(12))));
}
sqlSw.Stop();

Expand Down
26 changes: 26 additions & 0 deletions Lite/Services/RemoteCollectorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,32 @@ protected static int GetServerId(ServerConnection server)
return GetDeterministicHashCode(server.ServerName);
}

/// <summary>
/// Safely converts a SQL Server float/real value to decimal.
/// Returns 0 for Infinity, NaN, or values outside decimal range.
/// </summary>
protected static decimal SafeToDecimal(object value)
{
try
{
if (value is double d)
{
if (double.IsInfinity(d) || double.IsNaN(d))
return 0m;
}
else if (value is float f)
{
if (float.IsInfinity(f) || float.IsNaN(f))
return 0m;
}
return Convert.ToDecimal(value);
}
catch (OverflowException)
{
return 0m;
}
}

/// <summary>
/// Deterministic hash code for a string. .NET Core randomizes string.GetHashCode()
/// per process, so we use a simple FNV-1a hash to get a stable value across restarts.
Expand Down