How to build a real-time metrics dashboard for your MU Online server
Build a real-time metrics dashboard to monitor online players, uptime, CPU/RAM usage, slow queries, and your MU Online server's economy, using periodic collection, a time-series database, and a web panel for visualization.
Running a MU Online server "in the dark" — with no visibility into how many players are online right now, whether the database is under stress, or whether the economy is inflating — is like flying without instruments. A real-time metrics dashboard turns operational decisions (when to scale hardware,
Running a MU Online server "in the dark" — with no visibility into how many players are online right now, whether the database is under stress, or whether the economy is inflating — is like flying without instruments. A real-time metrics dashboard turns operational decisions (when to scale hardware, when to review a drop rate, when to investigate lag) from guesswork into hard data. This tutorial walks through building a complete dashboard: from collecting system and game metrics, through time-series storage, to visualization in a web panel and automatic alerts.
What's worth measuring
Before picking a tool, define what the dashboard needs to answer. A solid set of metrics for a MU server covers three layers:
| Layer | Metrics | Suggested frequency |
|---|---|---|
| Infrastructure | CPU, RAM, disk, network, service uptime | 5-15 seconds |
| Game server | Players online, ConnectServer connections, average latency | 15-30 seconds |
| Economy/game | Zen in circulation, Excellent items dropped/hour, resets/day | 5-15 minutes |
Infrastructure and game server metrics need high frequency because they change fast; economy metrics are aggregated and change slowly, so collecting every minute is already more than enough.
Prerequisites
- A MU server already running and configured.
- Access to the emulator's database (MSSQL or MySQL, depending on the emulator).
- A machine/VM (or the host itself) to run the monitoring stack.
- Basic scripting knowledge (PowerShell, Python, or Node.js) for the collectors.
Step 1 — Choose the monitoring stack
Two common routes:
- Ready-made stack (Prometheus + Grafana): Prometheus collects and stores time series; Grafana visualizes them. Steeper learning curve, but extremely extensible with native alerting.
- Lightweight custom panel: a collector script periodically writes metrics to a SQL table, and a simple web page (PHP/Node) queries and displays them via charts (Chart.js). Faster to set up, less flexible long-term.
For small/medium servers, start with the custom panel; migrate to Prometheus/Grafana once metric volume justifies it.
Step 2 — Create the time-series table (custom route)
CREATE TABLE metrics_snapshot (
id INT IDENTITY PRIMARY KEY,
captured_at DATETIME NOT NULL DEFAULT GETDATE(),
players_online INT NOT NULL,
cpu_percent DECIMAL(5,2),
ram_percent DECIMAL(5,2),
zen_total BIGINT,
excellent_drops_last_hour INT
);
This table grows fast if collected every few seconds — plan a cleanup routine (e.g., keep fine granularity for 7 days and aggregate into hourly averages afterward).
Step 3 — Write the infrastructure collector
A simple PowerShell (Windows) collector that writes CPU and RAM every 15 seconds:
while ($true) {
$cpu = (Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
$ram = (Get-CimInstance Win32_OperatingSystem)
$ramPercent = 100 - ($ram.FreePhysicalMemory / $ram.TotalVisibleMemorySize * 100)
Invoke-Sqlcmd -Query "INSERT INTO metrics_snapshot (cpu_percent, ram_percent) VALUES ($cpu, $ramPercent)"
Start-Sleep -Seconds 15
}
Run it as a service/scheduled task to make sure collection survives reboots.
Step 4 — Write the game metrics collector
Query the emulator's own connected accounts/characters table (the table/column name varies by emulator — usually something like MEMB_STAT or a connection flag in Character):
SELECT COUNT(*) AS players_online FROM MEMB_STAT WHERE ConnectStat = 1;
Store this value together with the aggregated economy (sum of Zen, count of Excellent drops in the last hour via the item log, if your emulator logs that).
Step 5 — Build the visualization (web panel)
A simple page querying the metrics_snapshot table and rendering it with Chart.js:
fetch('/api/metrics?range=1h')
.then(r => r.json())
.then(data => {
new Chart(document.getElementById('grafico-online'), {
type: 'line',
data: {
labels: data.map(d => d.captured_at),
datasets: [{ label: 'Players Online', data: data.map(d => d.players_online) }]
}
});
});
Build separate panels for: online count over the day, CPU/RAM, and economy (Zen in circulation, Excellent drops).
Step 6 — Add healthcheck and alerts
Set up a script that tests the ConnectServer/GameServer port every minute and fires a webhook to Discord if the check fails 3 times in a row (avoiding false alerts from momentary network instability):
$falhas = 0
while ($true) {
$ok = Test-NetConnection -ComputerName "127.0.0.1" -Port 44405 -InformationLevel Quiet
if (-not $ok) {
$falhas++
if ($falhas -ge 3) {
Invoke-RestMethod -Uri $webhookDiscord -Method Post -Body (@{content="⚠️ GameServer is down!"} | ConvertTo-Json) -ContentType 'application/json'
}
} else { $falhas = 0 }
Start-Sleep -Seconds 60
}
Step 7 — Monitor slow database queries
Enable your DBMS's slow query log (slow query log in MySQL, Query Store in SQL Server) and add a panel to the dashboard showing the slowest queries in the last hour. This often reveals bottlenecks before they turn into lag players can feel, especially during peak hours.
Step 8 — Define data retention and aggregation
Without a retention policy, the metrics table grows indefinitely. A reasonable scheme: keep 15-second granularity for 48h, aggregate into 5-minute averages for 30 days, and aggregate into daily averages indefinitely for long-term historical analysis.
Step 9 — Restrict access to sensitive data
Split the dashboard into two layers: a public (or semi-public, on the site) one with aggregated metrics (total online, uptime, current season) for community transparency, and an authenticated administrative one with sensitive details (IPs, specific accounts, individual logs).
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Metrics table grows uncontrollably | No retention/aggregation policy | Implement periodic cleanup and aggregation |
| Dashboard freezes or gets slow | Heavy queries directly on the raw table | Use aggregated views or short-term caching |
| False alerts about the server being down | Single check with no tolerance for network failures | Require N consecutive failures before alerting |
| Collection impacts GameServer performance | Overly aggressive collection frequency | Reduce frequency for heavy metrics (economy) |
| Sensitive data exposed publicly | Single panel with no access separation | Separate the public (aggregated) panel from the admin one |
Deployment checklist
- Infrastructure, game, and economy metrics defined and prioritized.
- Time-series table/stack created with a retention plan.
- System and game collectors running as a persistent service.
- Visualization panel built with charts for the key metrics.
- Healthcheck with webhook alerting configured and tested.
- Slow query monitoring enabled on the database.
- Separation between public (aggregated) and admin (detailed) panels.
With the dashboard live, you can make hardware scaling, economy tuning, and maintenance-window decisions based on real data instead of intuition — the next step is reviewing the server's base configuration described in the server creation tutorial in light of what the dashboard's numbers are revealing.
Frequently asked questions
Do I need Grafana, or can I build a simpler dashboard?
Grafana is the most robust free option, but for small servers, a custom web panel querying the database every few seconds (via AJAX/polling) already gets the job done. The choice depends on how much time you want to invest maintaining the tool.
Does collecting metrics every second overload the server?
Collecting every 1 second for heavy metrics (like counting online characters via a full query) can indeed generate unnecessary load. It's recommended to collect system metrics (CPU/RAM) every 5-15s and game metrics every 30-60s.
How do I monitor slow database queries?
Most DBMSs (MySQL/MSSQL) have a native slow query log (slow query log in MySQL, Query Store in SQL Server) that can be enabled and then consumed by your dashboard or by tools like Percona Toolkit.
Can I get automatic alerts when the server goes down?
Yes. Set up a healthcheck that periodically tests the GameServer/ConnectServer port and fires a webhook (Discord, Telegram) when the check fails N times in a row, avoiding false alerts from a single network hiccup.
Does the dashboard expose sensitive data if it's public?
It can, if you include individual player data (IP, email) without anonymization. Keep the public dashboard limited to aggregated metrics (total online, uptime, overall economy) and restrict detailed data to an authenticated admin panel.