Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

Server Monitoring Basics: What to Watch Before Your Users Complain

About Post

Every app has a monitoring system. For a lot of apps, it's called "customers". It works surprisingly well: it notices every outage. It just reports them late, angrily, and through the wrong channel.

Good monitoring isn't about fancy dashboards. It's about finding out that something is wrong a few minutes before anyone else does, and having enough information to know where to look. You can get most of the way there with a short list of signals and a handful of sensible alerts.

Symptoms vs causes

Before the list, one idea that changes how you set up alerts. There are two kinds of signals:

  • Symptoms are what users feel: the site is down, pages are slow, requests are failing, the email never arrived.
  • Causes are what the machine feels: CPU is high, memory is low, the disk is filling up, the queue is backing up.

Alert loudly on symptoms, because they always matter. Watch causes on dashboards and alert on them only when they predict a symptom that's coming. High CPU at 3 a.m. during a scheduled report isn't a problem. A disk that will be full by Friday is.

The machine: CPU, memory, disk

CPU

Short spikes are normal. What you care about is sustained high usage, and the load average on Linux, which tells you how many processes are running or waiting. A load consistently above your number of CPU cores means work is queueing up. Run uptime or htop to see it.

Memory

Linux happily uses spare memory for file caching, so "free memory is low" on its own means nothing. Look at available memory (the available column in free -h) and at swap. If the server starts swapping heavily, everything slows down. If it runs out completely, the kernel's OOM killer picks a process to kill, and it's often your database or PHP-FPM.

Disk

The most boring metric and the most common cause of a surprise outage. Logs grow, uploads pile up, old backups never get deleted, and one day MySQL can't write. Two things to watch:

  • Space used (df -h), and more importantly the trend. A disk going from 70% to 72% in a month is fine. 70% to 90% in a day is not.
  • Inodes (df -i). Millions of tiny files, like old session or cache files, can exhaust inodes while plenty of space is left. The error says "no space left on device" and df -h says you have space. Fun afternoon.

The application: speed and errors

Response times: use percentiles, not averages

The average response time is the most misleading number in monitoring. If most requests take 100 ms and a few take 10 seconds, the average looks fine while some users are having a terrible time.

Look at p95 and p99: the time within which 95% or 99% of requests finish. That's the experience of your unluckiest users, and they're often your heaviest ones (the account with the most data, the admin running the big report).

Error rate

Track the share of requests returning 5xx errors, plus exceptions from your application logs. An error tracker (Sentry, Flare, Bugsnag and similar) groups identical exceptions together, so a new type of error stands out instead of drowning in noise.

Track rates, not counts. Fifty errors in an hour means something very different at 100 requests per hour than at 100,000.

The invisible part: queues and scheduled jobs

This is where Laravel apps get hurt most quietly. When a queue worker dies, nothing crashes. The website loads fine. It's just that no emails go out, no PDFs are generated, no payments are reconciled, and nobody notices until someone asks why.

  • Queue depth: how many jobs are waiting. A queue that keeps growing means workers are down or too slow. Laravel Horizon shows this for Redis queues, and the queue:monitor command can fire an event when a queue passes a size you choose.
  • Failed jobs: a sudden jump in failed_jobs usually means an external API changed or went down.
  • Scheduled tasks: the scheduler fails silently if cron stops running it. Use a heartbeat: the task pings an external URL when it finishes, and you're alerted if the ping doesn't arrive. Laravel's scheduler has pingOnSuccess() for exactly this.
Schedule::command('invoices:send-reminders')
    ->dailyAt('08:00')
    ->pingOnSuccess(config('services.heartbeats.reminders'));

The view from outside: uptime checks

All the metrics above come from inside your server. If the server is down, or DNS is broken, or the certificate expired, the server can't tell you. You need something on the outside knocking on the door.

  • An uptime check that requests a real page every minute or so, from more than one location, and checks for a 200 response and some expected text.
  • A health endpoint that checks the database and cache connections, not one that returns "OK" no matter what. Laravel 11 and 12 ship with a /up route you can build on.
  • SSL certificate expiry and domain expiry warnings. Both are completely preventable outages that still happen to big companies.

A good alert is urgent, actionable and rare. If an alert fires and the right response is "ignore it", fix or delete that alert. A team that ignores alerts will ignore the real one too.

Alerts that people don't learn to ignore

  • Alert on duration, not blips. "Error rate above normal for 5 minutes" beats "an error happened".
  • Two levels. Page someone for "users are affected now". Send a message or ticket for "this will become a problem in days" (disk trend, certificate expiry).
  • Send it where people look. An email folder nobody opens is not an alerting channel.
  • Write the first step into the alert. "Queue depth high: check Horizon, then supervisorctl status" saves precious minutes at midnight.

A starter setup

SignalWatch on dashboardAlert when
Uptime / health checkYesFails from multiple locations
5xx error rateYesClearly above normal for several minutes
p95 response timeYesSustained jump well above your baseline
Queue depth / failed jobsYesKeeps growing, or failures spike
Scheduler heartbeatNoPing missing
Disk space and inodesYesTrend says full within days
Memory and swapYesHeavy swapping or OOM kills
CPU / loadYesRarely on its own
SSL and domain expiryNoA few weeks before expiry

Which tool you use matters less than covering these rows. Cloud providers have built-in metrics (CloudWatch on AWS), and there are plenty of hosted and open-source options for the rest. Start with the outside check and the queue, because those catch the outages that are otherwise invisible.

What's the one alert that has saved you most often? And which one did you finally delete because it cried wolf every night?

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close