Üretim ortamında hata olmaz. Olursa da haberimiz olmaz. Çünkü hata mesajlarını ekranda göstermek tehlikelidir. Zaten son kullanıcı hata mesajını görse de size raporlamaz. Raporlasa da o rapor bizim bir işimize yaramaz.
“Aynı hatayı tekrar oluşturup, problemin sebini anlamaya çalışıyoruz” denir, ürüne değer kaybettirilir. Biraz daha tecrübeli geliştiriciler, hemen log dosyasını tarar ama o kadar veri içinden gerçek hatayı bulup çıkarmak da ayrı bir ustalık işi.
Peki ne yapmamız gerekli?
Öncelikle, bir geliştirici, son kullanıcıdan, bir hata ile karşılaştığında ne ister ve bu isteği otomatik olarak nasıl gerçekleştiririz sorusunu cevaplamamız lazım.
- İyi bir hata raporunda ekran görüntüsü olmalı,
- hatanın oluştuğu dosya, dosyanın satır numarası hatta işlev (function) ve aldığı parametreler, bu işlevi hangi işlev çağırdı gibi sorularında yanıtı olmalı.
Burada en kolayı ikincisi. Eğer sunucu ile veri alışverişini AJAX ile yapıyorsak birincisi de kolay.
- ilk olarak uygulamamıza html2canvas kütüphanesini eklemeliyiz:
<script src="/assets/js/html2canvas/html2canvas.min.js"></script>
- Ana javascript fonksiyonumuza JQuery AJAX istekleri ile hata almamız durumunu yakalamalıyız.
$(document).bind('ajaxError',function(event,jqXHR, ajaxSettings, thrownError){ switch (jqXHR.status){ case 500: var responseTime = new Date(); html2canvas(document.body, { onrendered: function(canvas) { $.ajax({ url: REPORTING_URL, type: 'POST', data:{image:canvas.toDataURL("image/png"),"time":parseInt(responseTime.timestamp / 1000)}, success:function(response){ $.infoBox(lastMsg); } }); } }); break; } });
- Symfony tarafında oluşan hataları yakalamamız gerekiyor. Bunun için bir servis yazmamız gerkli. Yakaladığımız hatayı $_SESSION içine kaydedeceğiz. Ekran görüntüsü geldiğinde, ikisini birlikte gönderebilmek için
namespace YourNameSpace\YourBundle\Controller; use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; class MyExceptionListener { protected $templating; protected $kernel; public function __construct(EngineInterface $templating, $kernel) { $this->templating = $templating; $this->kernel = $kernel; } public function onKernelException(GetResponseForExceptionEvent $event) { $exception = $event->getException(); $_SESSION["last_error_message"]=$exception->xdebug_message; } }
- Servis tanımlamalarını services.yml içinde yapıyoruz:
services: kernel.listener.selphiu_exception_listener: class: YourNameSpace\YourBundleBundle\Controller\MyExceptionListener arguments: [@templating, @kernel] tags: - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
- Hata raporunun gönderileceği email adresini parameters.yml içine ekliyoruz
parameters: error_reporting_email_address: '[email protected]' mailer_transport: smtp mailer_host: mail.domain.com mailer_user: [email protected] mailer_password: PASSWORD mailer_port: 587
- İkinci adımda REPORTING_URL ile belirttiğimiz adresi dinleyen bir Action yazmamız gerekiyor. Bu action, ekran görüntüsü ile $_SESSION içindeki hata raporunu paketleyip email yoluyla bize gönderecek. Bunu yaparken error_report.html.twig isminde bir twig template’inizin zaten var olduğunu varsayıyorum
namespace YourNameSpace\YourBundle\Controller; use Monolog\Handler\StreamHandler; use Monolog\Logger; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Validator\Constraints\DateTime; class ErrorReportingController extends AuthBaseController{ public function reportAction(Request $request){ $imageDataURL = $request->get("image"); $parts = explode(",",$imageDataURL); $data = $parts[1]; $data = base64_decode($data); $time = $request->get("time"); $messageText = $_SESSION["last_error_message"]; $reportingAddress = $this->container->getParameter("error_reporting_email_address"); $attachment = \Swift_Attachment::newInstance() ->setFilename('snapshot.png') ->setContentType('image/png') ->setBody($data) ; $message = \Swift_Message::newInstance() ->setSubject("[Project-Error] Report") ->setFrom(array($this->container->getParameter('mailer_user')=>"Project Reporter")) ->setTo($reportingAddress) ->setContentType("text/html") ->setBody($this->renderView('YourBundle:EMail:error_report.html.twig', array( 'message' => $messageText, ) ) )->attach($attachment) ; $this->get('mailer')->send($message); $response = new Response(json_encode(array("status"=>"OK","result"=>array()))); $response->headers->set("Content-Type","application/json"); return $response; } }