Website uptime monitor with Laravel

website တစ်ခု down နေလား up နေလားစစ်ပေးတဲ့ application ကို Laravel နှင့်ရေးသားမှာဖြစ်ပါတယ်... ဒီအပိုင်းကအပိုင်း ၁ ဖြစ်ပြီးတော့ terminal ကနေ website တွေ monitor လုပ်ဖို့ command ကနေထည့်နိုင်ဖို့ရေးသားမှာဖြစ်ပါတယ်။

Posted by Set Kyar Wa Lar (universe) on 5 months ago

ဒီနေ့ကျွန်တော်တို့ create လုပ်မယ့် App ကတော့ Laravel နဲ့ website up/down စစ်တဲ့ application ဘဲဖြစ်ပါတယ်။ Series ဖြစ်ပါ့လိမ့်မယ်။ ပထမဆုံး command line app ကိုရေးသားဖော်ပြပေးသွားမှာဖြစ်ပြီးတော့ နောက်ပိုင်းမှာ UI နှင့်တစ်ခြား webhooks ကိုပါကိုယ်ပိုင် implement လုပ်ပြပေးသွားမှာဘဲဖြစ်ပါတယ်။

ကျွန်တော်တို့ဒီနေ့အပိုင်းမှာတော့ terminal ကနေ monitor လုပ်ဖို့ websites တွေကိုထည့်လို့ရမယ်။ ထည့်ထားတဲ့ website ရဲ့ status ကိုစစ်ဖို့ command ရှိမယ်။ လောလောဆယ် Application Name ကိုတော့ ping လို့ပေးထားတယ်။

ပထမဆုံးကျွန်တော်တို့ပုံမှန်အတိုင်းဘဲ Laravel ကို install လုပ်လိုက်ပါ။ laravel new ping ဆိုပြီးတော့ Laravel ကို install လုပ်ပြီးသွားပြီဆိုရင်။ ကျွန်တော်တို့ migration အတွက်စဥ်းစားကြမယ်။ ကျွန်တော်လောလောဆယ်စဥ်းစားထားတာကတော့ end_points ဆိုတဲ့ table ရယ် statuses ဆိုတဲ့ table နှစ်ခုရှိမယ်။ Enpont table ထဲမှာ uri ရယ် frequency ရယ်နှစ်ခုရှိမယ်။ statuses ကတော့ endpoint နဲ့ချိတ်ထားမယ် one to many နဲ့ပေါ့... frequency ပေါ်မူတည်ပြီးတော့ endpoint ထဲက website ကိုသွားပြီးတော့ check မယ်... ရလာတဲ့ result ကို statuses ဆိုတဲ့ table ထဲမှာသွားထည့်ထားမယ်။

ပထမဆုံး migration မလုပ်ခင် .env မှာကိုယ့်စက်က database နှင့်ကိုက်ညီတဲ့ username, password နှင့် table တို့ကို update လုပ်လိုက်ပါ။ ပြီးရင်ခုနကကျွန်တော်တို့ပြောခဲ့တဲ့အတိုင်း table နှစ်ခုအတွက်အောက်ဖော်ပြပါ command နှစ်ခုကို run လိုက်ပါ။

php artisan make:model EndPoint -m
php artisan make:model Status -m

အခုဆိုရင်ကျွန်တော်တို့ EndPoint ဆိုတဲ့ model နှင့် Status ဆိုတဲ့ model နှစ်ခုရသွားပြီ။ ကျွန်တော်တို့ -m ဆိုပြီးထည့်ခဲ့တဲ့အတွက် migration file တွေပါ generate လုပ်ပေးထားပြီးဖြစ်ပါတယ်။

Schema::create('end_points', function (Blueprint $table) {
    $table->id();
    $table->string('uri');
    $table->integer('frequency');
    $table->timestamps();
});

end_points migration အတွက်အထက်ဖော်ပြပါအတိုင်း update လုပ်လိုက်ပါ။ နောက်အောက်ဖော်ပြပါအတိုင်း statuses migration ကို update လုပ်လိုက်ပါ။

Schema::create('statuses', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('end_point_id');
    $table->integer('status_code');
    $table->timestamps();
});

Update လုပ်ပြီးသွားရင် php artisan migrate လုပ်လိုက်ပါ။ အခုဆိုရင် ကျွန်တော်တို့ migration ပြင်ဆင်တာပြီးပါပြီ။


နောက်တစ်ဆင့်ကတော့ command တွေ create လုပ်ဖို့ဘဲဖြစ်ပါတယ်။ ဘာတွေလဲဆိုတာအောက်က list မှာတစ်ချက်ကြည့်လိုက်ကြရအောင်

  • ping:add-url-to-monitor (Monitor လုပ်ချင်တဲ့ URL ထည့်ရန် command)
  • ping:monitor-up-time (Monitor လုပ်ဖို့ရာအတွက်ထည့်ထားတဲ့ URL တွေကို frequency အလိုက်စစ်ရန်)
  • ping:status (Monitor လုပ်ထားတဲ့ URL ရဲ့ status ကိုကြည့်ရန်)

ပထမဆုံး monitor လုပ်ချင်တဲ့ URL ကိုဘယ်မိနစ်တစ်ခါစစ်ချင်လဲဆိုတာကိုပါ တစ်ခါတည်းထည့်လို့ရတဲ့ command create လုပ်ဖို့အောက်ဖော်ပြပါ command ကို run လိုက်ပါ...

php artisan make:command AddURLToMonitor

အဲ့ကျရင် App\Console\Command ထဲမှာ AddURLToMonitor ဆိုတဲ့ class တစ်ခုတည်ဆောက်ပေးထားပါ့လိမ့်မယ်... ကျွန်တော်တို့ကအဲ့ကောင်ပေါ်အခြေခံပြီးလိုအပ်တာလေးတွေပြင်ပါ့မယ်... လောလောဆယ်အောက်ဖော်ပြပါ code နှင့် update လုပ်လိုက်ပါ...

<?php

namespace App\Console\Commands;

use App\EndPoint;
use Illuminate\Console\Command;

class AddURLToMonitor extends Command
{
  /**
   * The name and signature of the console command.
   *
   * @var string
   */
  protected $signature = 'ping:add-url-to-monitor
                {url : URL to monitor}
                {--frequency=1 : Frequnecy in minutes}';

  /**
   * The console command description.
   *
   * @var string
   */
  protected $description = 'Add url to monitor.';

  /**
   * Execute the console command.
   *
   * @return mixed
   */
  public function handle()
  {
    $url = $this->argument('url');
    $frequency = $this->option('frequency');

    EndPoint::create([
      'uri' => $url,
      'frequency' => $frequency,
    ]);

    $this->info('Successfully added the URL to monitor.');

    $headers = ['URI', 'Frequency', 'Added At'];

    $endpoints = EndPoint::all(['uri', 'frequency', 'created_at'])->toArray();

    $this->table($headers, $endpoints);
  }
}

ကျွန်တော်တို့ signature ကိုပြင်လိုက်တယ်... URL ထည့်လို့ရမယ်... frequency က default 1 ထည့်ထားတယ် minutes ဖြစ်လို့ 1 ကနေ 59 ထိဘဲထည့်လို့ရမယ်ဆိုတာကို validate မစစ်ခဲ့သေးဘူး။ URL ရပြီဆိုရင် Endpont table ထဲမှာ uri နှင့် frequnecy ထဲမှာထည့်ပြီးတော့သိမ်းလိုက်တယ်။ ပြီးတော့ success message ပြလိုက်တယ်။ success message ပြပြီးတဲ့အခါမှာ table နှင့်ပါပြလိုက်တယ်... ဘယ် URI တွေထည့်ထားတယ်ဆိုတာကို... အောက်ဖော်ပြပါအတိုင်းမြင်ရမှာဖြစ်တယ်...

URL ထည့်ပြီးတဲ့အခါမြင်ရသော result

URL ထည့်ပြီးတဲ့အခါမြင်ရသော result

ကျွန်တော်တို့ဒီအပိုင်းပြီးသွားတဲ့အခါမှာ ဒီထည့်ထားတဲ့ URI တွေကို Frequency ပေါ်မူတည်ပြီးတော့စစ်တဲ့ command ရေးပါ့မယ်။ အထက်မှာလိုဘဲ MonitorUpTime ဆိုတဲ့ command ရေးဖို့အတွက် php artisan နှင့် generate လုပ်ဖို့ရာဒီ command ကို run လိုက်ပါ php artisan make:command MonitorUpTime ... App\Console\Command ထဲမှာ MonitorUpTime ဆိုတဲ့ class တစ်ခုဆောက်ပေးတဲ့အခါမှာ အောက်ဖော်ပြပါ code နှင့် update လုပ်လိုက်ပါ။

<?php

namespace App\Console\Commands;

use App\EndPoint;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Http\Client\ConnectionException;

class MonitorUpTime extends Command
{
  /**
   * The name and signature of the console command.
   *
   * @var string
   */
  protected $signature = 'ping:monitor-up-time';

  /**
   * The console command description.
   *
   * @var string
   */
  protected $description = 'Monitor endpont URLs';

  /**
   * Execute the console command.
   *
   * @return mixed
   */
  public function handle()
  {
    $endponts = EndPoint::all();

    foreach($endponts as $endpont)
    {
      if(!$endpont->isDue()) {
        continue;
      }

      $response = Http::get($endpont->uri);

      $endpont->statuses()->create([
        'status_code' => $response->status(),
      ]);
    }
  }
}

ဒီ command မှာတော့ထွေထွေထူးထူး argument တွေမပါဘူး... ဒီကောင်က App\Console\Kernal ကနေပြီးတော့ minute တိုင်း run ရမယ့်ကောင်ဖြစ်တယ်။ ပထမဆုံး Handle ထဲကကောင်ကိုတစ်ချက်အရင်ရှင်းပြလိုက်မယ်... Endpoints ထဲကကောင်တွေအကုန်လုံးကို query ဆွဲလိုက်တယ်... ပြီးတော့ loop ပတ်ပြီးတော့ ဒီ endpoint ကိုစစ်ရမယ့် frequency မှာဟုတ်မဟုတ်စစ်လိုက်တယ်... မဟုတ်သေးဘူးဆိုရင်သူ့ကို skip သွားမယ်။ ဟုတ်တယ်ဆိုရင် Http::get သုံးပြီးတော့ endpoint->uri ကို request လုပ်လိုက်တယ်။ ပြီးတော့ endpont ထဲက statuses ထဲမှာ status_code ကိုသိမ်းလိုက်တယ်။

ဒီအပိုင်းမှာကျွန်တော်တို့ relationship ချိတ်တဲ့အပိုင်းတွေပါပေမယ့်မချိတ်ရသေးတာ့စမ်းမယ်ဆိုရင် error တက်ပါလိမ့်မယ်။ အဲ့တော့ relationship ချိတ်ဖို့ရာအတွက် Endpoint model မှာ အောက်ဖော်ပြပါ method နှစ်ခုကိုသွားထည့်ပေးပါ။

  /**
   * The attributes that are mass assignable.
   *
   * @var array
   */
  protected $fillable = ['uri', 'frequency'];

  public function statuses()
  {
    return $this->hasMany(Status::class);
  }

  public function isDue() : bool
  {
    $expression = "*/{$this->frequency} * * * *";

    return Cron\CronExpression::factory($expression)->isDue(Carbon::now());
  }

Method တင်မကဘူး mass assignable အတွက်ပါ fillable ပါထည့်ပေးလိုက်ပါ။ statuses ကတော့ relationship အတွက်ဖြစ်ပါတယ်။ isDue ကတော့ website ထည့်ထားတဲ့ endpoint ကို frequency မိနစ်ပေါ်မူတည်ပြီးတော့ cron run ကမှာလားဆိုတာစစ်တဲ့ကောင်ပါ။

နောက် Status model မှာလည်းအောက်ဖော်ပြပါအတိုင်း update လုပ်လိုက်ပါ...

/**
   * The attributes that are mass assignable.
   *
   * @var array
   */
  protected $fillable = ['status_code'];

  public function endpont()
  {
    return $this->belongsTo(EndPoint::class);
  }

အခုဆိုရင်ကျွန်တော်တို့ uptime monitor app ဖြစ်တဲ့ ping မှာ monitor လုပ်ဖို့ website url တွေကို frequency ပေါ်မူတည်ပြီးထည့်လို့ရပြီ။ ထည့်ထားတဲ့ URI တွေကိုစစ်ပေးတဲ့ monitor command လည်းပြီးသွားပြီ။ ဒါဆိုရင် local မှာ cron နှင့်ဘယ်လိုစမ်းမလဲဆိုတာလေးကြည့်လိုက်ရအောင်...

ပထမဆုံးကျွန်တော်တို့ status ok တဲ့ website တစ်ခုကိုမိနစ်တိုင်းစစ်ဖို့ အောက်ဖော်ပြပါ command ကို run ပြီးတော့ထည့်လိုက်ကြရအောင်...

php artisan ping:add-url-to-monitor google.com

ပြီးသွားပြီဆိုလို့ရှိရင် manually monitor command ကို run ဖို့ အောက်ဖော်ပြပါ command ကို run လိုက်ပါ...

php artisan ping:monitor-up-time

ပြီးရင်ကျွန်တော်တို့ DB ထဲက statuses table ကိုသွားကြည့်လိုက်ရင် status_code 200 နှင့်အောက်ဖော်ပြပါအတိုင်းမြင်ရပါလိမ့်မယ်။

အခုဆိုရင် ကျွန်တော်တို့ရဲ့ uptime monitor ရဲ့လိုအပ်တဲ့ basic command နှစ်ခုပြီးသွားပါပြီ... နောက်ပိုင်းတဖြည်းဖြည်း UI ပါထည့်မှာမလို့ နောက် article တွေကိုဆက်လက်စောင့်မျှော်ဖတ်ရှုကြပါဦးလို့...

အခုဒီအပိုင်းက code တွေကို Github မှာတင်ထားပါတယ်။ တကယ်လို့မရှင်းတာရှိရင် comment section မှာမေးခွန်းမေးနိုင်ပါတယ်။ သို့မဟုတ် Laravel Myanmar Telegram မှာလည်း error အကြောင်းနှင့်ပတ်သတ်လို့မေးနိုင်ပါတယ်။

ဒုတိယအပိုင်းကို ဒီမှာ ဖတ်နိုင်ပါပြီ။

Hey, I am Set Kyar Wa Lar. Software Engineer at Carro. Maintainer of Laravel Myanmar and creator of MyanmarDevJobs.