I've been working on a PowerShell-based monitoring dashboard for our organization's content caching servers, and I recently made some significant improvements that have transformed it from a basic reporting tool into a comprehensive analytics solution. The dashboard monitors multiple cache servers across our network, providing real-time insights into data transfer, bandwidth savings, and system health.
In this post, I'll walk through the enhancements I made to the original script, explaining the reasoning behind each change and showing the code that makes it all work.
What This Dashboard Does
The dashboard processes CSV log files from our caching servers (like macOS Caching Server stats) and generates an HTML report that includes:
- A visual chart showing cache transfer statistics over time
- Health status cards for each cache server
- Metrics showing data served to clients vs. data fetched from origin servers
- Bandwidth savings calculations (the key metric for understanding cache efficiency)
The Problem: The original dashboard only showed the last 30 data points, which gave us about 30 hours of history (assuming hourly logs). This wasn't enough to spot trends or patterns over multiple days.
The Solution: I increased the data points to 120, providing 5 days of historical data.
function Process-CacheData {
param($filePath, $numLines = 120) # Changed from 30 to 120
if (!(Test-Path $filePath)) {
Write-Warning "File not found: $filePath"
return $null
}
$data = Import-Csv $filePath | Select-Object -Last $numLines
# ... rest of processing
}
This simple change gives us much better visibility into weekly patterns and helps identify issues that might not be apparent in just a day's worth of data.
Enhancement 2: Removing X-Axis Labels for Clarity
The Problem: With 120 data points on the chart, the date/time labels on the X-axis became completely unreadable - they overlapped and created visual clutter.
The Solution: I removed the X-axis labels entirely and switched to using simple index numbers internally.
# Use index numbers instead of dates for X-axis
$indices = 1..$data.Count
# ... process data ...
return @{
indices = "[" + ($indices -join ",") + "]"
toClients = "[" + ($toClients -join ",") + "]"
fromOrigin = "[" + ($fromOrigin -join ",") + "]"
}
And in the Chart.js configuration:
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Data Transfer (GB/hr)'
}
},
x: {
display: false // Hide the X-axis completely
}
}
The result is a clean, readable chart that shows trends without the distraction of overlapping labels.
Enhancement 3: Out-of-Hours Health Status
The Problem: Our caching servers naturally show zero activity outside business hours (6pm to 8am on weekdays, plus all day on weekends), which was incorrectly flagging healthy servers as "Unhealthy" during nights and weekends.
The Solution: I added time-aware health checking that recognizes out-of-hours periods, including full weekend coverage.
# Get current hour and day to determine if out of hours
# Out of hours: 6pm-8am on weekdays (18:00-08:00) OR all day Saturday/Sunday
$currentHour = (Get-Date).Hour
$currentDay = (Get-Date).DayOfWeek
$isWeekend = $currentDay -eq 'Saturday' -or $currentDay -eq 'Sunday'
$isOutOfHours = $isWeekend -or ($currentHour -lt 8 -or $currentHour -ge 18)
# Site is healthy if any of the last 4 values is non-zero (only check during business hours)
$isHealthy = if ($isOutOfHours) {
$true # Always healthy out of hours
} else {
($lastValues | Where-Object { $_ -gt 0 }).Count -gt 0
}
The HTML output now displays three possible statuses:
$healthStatus = if ($_.outOfHours) {
"<span class='health-status out-of-hours'><span>●</span> Healthy - Out of Hours</span>"
} elseif ($_.healthy) {
"<span class='health-status healthy'><span>●</span> Healthy</span>"
} else {
"<span class='health-status unhealthy'><span class='blink'>●</span> Unhealthy</span>"
}
This eliminated false alarms throughout evenings and weekends, giving us confidence that the monitoring is accurate 24/7. The system now understands our business hours (Monday-Friday, 8am-6pm) and doesn't raise unnecessary alerts when users simply aren't in the office.
Enhancement 4: Adding 24-Hour Metrics
The Problem: The original dashboard showed total data transfer across the entire log file, which could span weeks or months. This made it difficult to understand current performance.
The Solution: I added dedicated 24-hour metrics alongside the total metrics, giving us both short-term and long-term visibility.
# Get last 24 hours of data (assuming hourly data)
$last24Hours = $data | Select-Object -Last 24
# Calculate Total Client Data Served (last 24 hours)
$clientDataServed24 = ($last24Hours | ForEach-Object {
if ($_.to_clients_since_last_gb -match "^\d*\.?\d*$") {
[double]$_.to_clients_since_last_gb
} else {
0
}
} | Measure-Object -Sum).Sum
# Calculate Total Internet Traffic (last 24 hours)
$internetTraffic24 = ($last24Hours | ForEach-Object {
if ($_.from_origin_since_last_gb -match "^\d*\.?\d*$") {
[double]$_.from_origin_since_last_gb
} else {
0
}
} | Measure-Object -Sum).Sum
I then repeated this calculation for the total (all data in the log file):
# Calculate TOTAL (all data in log file)
$clientDataServedTotal = ($data | ForEach-Object {
if ($_.to_clients_since_last_gb -match "^\d*\.?\d*$") {
[double]$_.to_clients_since_last_gb
} else {
0
}
} | Measure-Object -Sum).Sum
$internetTrafficTotal = ($data | ForEach-Object {
if ($_.from_origin_since_last_gb -match "^\d*\.?\d*$") {
[double]$_.from_origin_since_last_gb
} else {
0
}
} | Measure-Object -Sum).Sum
Enhancement 5: Bandwidth Savings Calculations
The Key Metric: The most important metric for a caching server is how much bandwidth it saves by serving content from cache instead of fetching it from the internet every time.
I calculate this as the difference between what was served to clients and what was actually downloaded from the origin:
# Calculate Bandwidth Savings (24 hours)
$bandwidthSavings24 = $clientDataServed24 - $internetTraffic24
$savingsPercent24 = if ($clientDataServed24 -gt 0) {
($bandwidthSavings24 / $clientDataServed24) * 100
} else {
0
}
# Calculate Bandwidth Savings (Total)
$bandwidthSavingsTotal = $clientDataServedTotal - $internetTrafficTotal
$savingsPercentTotal = if ($clientDataServedTotal -gt 0) {
($bandwidthSavingsTotal / $clientDataServedTotal) * 100
} else {
0
}
This gives us both the absolute savings in GB and the percentage, making it easy to see cache efficiency at a glance.
Enhancement 6: Improved Metric Labels and Display
I renamed and reorganized the metrics to be more descriptive and business-focused:
<div class='metric'>
<div class='metric-label'>Total Client Data Served (24Hrs)</div>
<div class='metric-value'>$($_.clientDataServed24) GB</div>
</div>
<div class='metric'>
<div class='metric-label'>Total Internet Traffic (24Hrs)</div>
<div class='metric-value'>$($_.internetTraffic24) GB</div>
</div>
<div class='metric'>
<div class='metric-label'>Bandwidth Savings (24Hrs)</div>
<div class='metric-value savings'>$($_.bandwidthSavings24) GB ($($_.savingsPercent24)%)</div>
</div>
The bandwidth savings are displayed in green to highlight this positive metric:
.metric-value.savings {
color: #00c800;
font-weight: 600;
}
The Complete Metric Suite
Each cache server card now displays eight comprehensive metrics:
- Last Four Transfers - Recent activity trend with up/down indicator
- Total Client Data Served (24Hrs) - How much data clients received in the last day
- Total Internet Traffic (24Hrs) - How much we actually downloaded from the internet
- Bandwidth Savings (24Hrs) - The difference, showing cache efficiency
- Total Client Data Served (Total) - Historical total across all logs
- Total Internet Traffic (Total) - Historical internet usage
- Bandwidth Savings (Total) - Historical savings
- Status - Real-time health with out-of-hours awareness
Conclusion
What started as a basic reporting script has evolved into a powerful monitoring solution. By focusing on the metrics that matter most - bandwidth savings - and adding intelligent time-aware health checking, I've created a tool that provides real business value.