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

Uptime and Error Monitoring for Small Teams: A Setup You Can Finish This Week

About Post

Big companies have on-call rotations, observability platforms and people whose whole job is reliability. Small teams have a group chat and a customer who emails "is the site down?"

That's backwards in one important way: small teams need good monitoring more, because there's nobody else watching. The good news is that a solid setup for a small team isn't a big project. It's five layers, mostly built from things you already have, and you can finish it in a week of spare hours.

Here's the setup I'd recommend for a typical Laravel app with a web front end and maybe a mobile app, in the order I'd build it.

Layer 1: a health endpoint that tells the truth

Everything else builds on one URL that answers "is the app OK?" Laravel 12 ships one out of the box: /up, registered in bootstrap/app.php with health: '/up'. It returns 200 if the application boots.

That's a start, but "the app boots" isn't the same as "the app works". If the database is down, /up can still happily say yes. You can add your own checks by listening for the event Laravel fires when the endpoint is hit. If a listener throws, the endpoint returns a 500:

use Illuminate\Foundation\Events\DiagnosingHealth;

// AppServiceProvider::boot()
Event::listen(DiagnosingHealth::class, function () {
    DB::select('select 1');          // throws if the database is unreachable
    Cache::store()->get('health');   // throws if the cache is unreachable
});

A few rules for health checks:

  • Keep them fast and cheap. They'll be called every minute, forever. No heavy queries.
  • Check dependencies you can't work without, not every external API. If a third-party service is down, your health check failing too just adds noise.
  • Don't leak details. A public endpoint shouldn't print versions, hostnames or error messages.

Layer 2: uptime checks from outside

A monitor running on your own server can't tell you the server is gone. Uptime checks have to come from outside: a hosted uptime service that requests your health URL every minute or so, from several locations, and alerts you when it fails.

Set up checks for:

  • The health endpoint (is the app working?).
  • The homepage or login page (is the thing users see working?).
  • The API base URL your mobile app uses.
  • Certificate expiry, which most uptime services can watch too.

Make the monitor confirm the failure from more than one location, or after a second attempt, before it alerts. One dropped packet shouldn't wake anyone up.

Layer 3: error tracking

Uptime tells you the site is up. It says nothing about the checkout page throwing an exception for some of your users. That's the job of an error tracker: Sentry, Flare, Bugsnag and Rollbar are common choices with Laravel and JavaScript support.

What makes error tracking useful instead of noisy:

  • Grouping. The same exception from the same place becomes one issue with a count, not a flood of emails.
  • Alert on new issues, not every occurrence. "A new type of error appeared after the last deploy" is the alert you want.
  • Release tagging. Send the release version or commit hash, so you can see which deploy introduced a problem.
  • All your clients. Install it in the web front end and the mobile app too. Many bugs never reach your server logs at all.
  • Scrub personal data. Configure it so passwords, tokens and personal details aren't sent with error reports.

Layer 4: the jobs nobody is watching

Scheduled tasks and queues fail silently. The nightly reconciliation stops running and nobody notices, because nothing visibly broke. Uptime checks can't see this, and error trackers only see errors, not things that never started.

The fix is a heartbeat (sometimes called a dead man's switch): the job pings a monitoring URL each time it succeeds, and the monitor alerts when the ping doesn't arrive on time. Laravel's scheduler has this built in:

// routes/console.php
Schedule::command('payments:reconcile')
    ->dailyAt('02:00')
    ->pingOnSuccess(config('services.heartbeats.reconcile'))
    ->pingOnFailure(config('services.heartbeats.reconcile_fail'));

Do the same for the queue: a small scheduled job that pings a heartbeat proves that the scheduler is running and that workers are processing jobs. If either stops, you hear about it.

Layer 5: alerts that reach the right person

This is where most small-team setups fail. Not because nothing alerts, but because everything alerts to the same channel, and after the third false alarm, people stop looking.

SeverityExamplesGoes to
UrgentSite down, payments failing, health check redA phone notification for whoever is responsible this week
TodayNew error type after a deploy, heartbeat missed, queue backing upThe team chat channel
This weekCertificate expiring soon, disk filling slowly, recurring minor errorsA ticket or task

Two habits make this work. First, one named owner at a time, rotating weekly if there are a few of you, so "someone will look at it" becomes "Sara will look at it". Second, every alert that fired for nothing gets fixed or deleted the same week. Noisy alerts are worse than no alerts, because they teach everyone to ignore the real one.

Bonus: a status page

A simple status page, hosted somewhere other than your own servers, lets you tell users "we know, we're on it" in one place. It cuts down support messages during an incident and builds trust out of a bad moment. Many uptime services include one, and it takes minutes to set up.

The test: if your app broke at 3 AM tonight, how would you find out? If the honest answer is "a customer would tell us", start with layers 1 and 2 this week.

The starter checklist

  • Health endpoint with real dependency checks.
  • External uptime checks on health, login and API, plus certificate expiry.
  • Error tracking on backend, web and mobile, with release tags and data scrubbing.
  • Heartbeats for scheduled tasks and queues.
  • Three severity levels, one owner, and a habit of deleting noisy alerts.

None of this needs a dedicated reliability team. It needs an afternoon per layer and someone who cares.

What's the one alert that has saved you the most times? And which one did you finally delete because it never stopped crying wolf?

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