Giter Club home page Giter Club logo

cakephp-error-email's Introduction

ErrorEmail plugin for CakePHP 3.x

Build Status codecov License

The ErrorEmail plugin is designed to enhance CakePHP's error handling system by adding the ability to conditionally email the dev team when errors or exceptions are thrown by your application with useful debugging information such as:

  • Exception/Error Url
  • Exception/Error Class
  • Exception/Error Message
  • Exception/Error Code
  • Client IP
  • File and Line Number
  • Stack Trace

Screenshot

Table of Contents

Installation

You can install this plugin into your CakePHP application using composer.

Run the following command

composer require ebrigham1/cakephp-error-email

You can then load the plugin using the shell command:

bin/cake plugin load -b ErrorEmail

Or you can manually add the loading statement in the config/boostrap.php file of your application:

Plugin::load('ErrorEmail', ['bootstrap' => true]);

In your config/Bootstrap.php replace:

use Cake\Error\ErrorHandler;

With:

use ErrorEmail\Error\ErrorHandler;

In your src/Application.php replace:

use Cake\Error\Middleware\ErrorHandlerMiddleware;

With:

use ErrorEmail\Middleware\ErrorHandlerMiddleware;

Configuration

Default configuration:

'ErrorEmail' => [
    'email' => false,
    'emailLevels' => ['exception', 'error'],
    'emailDeliveryProfile' => 'default',
    'skipEmail' => [],
    'throttle' => false,
    'throttleCache' => '_error_email_',
    'skipThrottle' => [],
    'toEmailAddress' => null,
    'fromEmailAddress' => null,
    'environment' => null,
    'siteName' => null
],
'Cache' => [
    '_error_email_' => [
        'className' => 'File',
        'prefix' => 'error_email_',
        'path' => CACHE . 'error_emails/',
        'duration' => '+5 minutes'
    ],
],

This configuration is automatically merged with your application specific configuration preferentially using any keys you define.

  • email (bool) - Enable or disable emailing of errors/exceptions
  • emailLevels (array) - The email levels that should be used to determine what errors/exceptions are emailed. Valid levels are ['exception', 'error', 'warning', 'notice', 'strict', 'deprecated']. Each level is used to capture the following exceptions/php errors:
    • 'exception' - \Exception (all user/framework thrown exceptions)
    • 'error' - \Error, E_PARSE, E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR
    • 'warning' - E_WARNING, E_USER_WARNING, E_COMPILE_WARNING, E_RECOVERABLE_ERROR
    • 'notice' - E_NOTICE, E_USER_NOTICE
    • 'strict' - E_STRICT
    • 'deprecated' - E_DEPRECATED, E_USER_DEPRECATED,
  • emailDeliveryProfile (string) - The email delivery profile (defined in config/app.php under the Email key) to use "default" is the default
  • skipEmail (array) - An array of exception/error classes that should never be emailed even if they are thrown Ex: [Cake\Network\Exception\NotFoundException::class, Cake\Network\Exception\InvalidCsrfTokenException::class]
  • throttle (bool) - Enable or disable throttling of error/exception emails. Throttling is only performed if its been determined the exact same exception/error has already been emailed by checking the cache. Errors/Exceptions are determined to be unique by exception/error class + exception/error message + exception/error code
  • throttleCache (string) - The cache configuration to use for throttling emails, the default is using the file cache driver with a 5 minute duration
  • skipThrottle (array) - An array of exception/error classes that should never be throttled even if they are thrown more than once within the normal throttling window Ex: ['App\Exception\FullfillmentException'] These should be exceptions/errors you always want an email about every single time even if it spams your inbox.
  • toEmailAddress (string) - The email address to send these error/exception emails to, typically the dev team. This will override the to address provided by the email delivery profile if both are present.
  • fromEmailAddress (string) - The email address these emails should be sent from ex: [email protected]. This will override the from address provided by the email delivery profile if both are present.
  • environment (string) - Optional, with the default template this will be placed in both the subject and the body of the email so its easy to identify what environment the email was sent from Ex: local/staging/production.
  • siteName (string) - Optional, with the default template this will be placed in both the subject and the body of the email so its easy to identify what site the email was sent from.

Note: the skipLog key from Error in your config/app.php file is also used. Exception/Error classes that are in that list will not be emailed out as it is assumed if they aren't important enough to even log they shouldn't be important enough to receive an email about.

Important: If email => true you must provide a valid email delivery profile to the emailDeliveryProfile config key. Typically the default will work fine unless you've renamed your application's default email delivery profile. If your email delivery profile doesn't define a to address and a from address you must also define the toEmailAddress and fromEmailAddress config values. If throttle => true then throttleCache must also be a valid cache configuration. The default should work fine as long as you don't redefine throttleCache in your config.

A configuration exception will be thrown if the config is detected to be invalid with an explination of what is incorrect.

Basic Usage

Typically you define these keys in your config/app.php file:

'ErrorEmail' => [
    'email' => true,
    'skipEmail' => [],
    'throttle' => true,
    'skipThrottle' => [],
    'toEmailAddress' => '[email protected]',
    'fromEmailAddress' => '[email protected]',
    'environment' => 'production',
    'siteName' => 'yoursite.com'
],

With this configuration you would get emails whenever any fatal error or exception happened on your site with detailed debugging information in the email. If say you had an error on a popular page that many users were hitting that error would only be sent to you once every 5 minutes for the duration of the error being in existence. If a different error was thrown as well you would get that error right away the first time but then again it would be throttled to a maximum of once every 5 minutes.

If you found that you were receiving a lot of emails for exceptions/errors that you can not do anything about for instance Cake\Network\Exception\NotFoundException you can simply add it to the skipEmail config and you will no longer be bothered with those exceptions.

If you want to throttle emails in general to avoid spamming your team, but you have some exceptions that you must always receive an email about then you can use the skipThrottle list. For instance maybe a customer has paid for something on your site, but you were unable to fulfill their purchase after they paid because it requires an API call to a service that was temporarily down. Then you can add the exception you throw in that instance to the skip throttle list. This will result in all exceptions aside from the exceptions you define in the skipThrottle list being throttled to only email once per every 5 minutes while your FullfillmentException will email you every single time it happens.

Advanced Usage

Overriding Views

The default plugin email templates can be overridden by creating your own template files at:

  • src/Template/Plugin/ErrorEmail/Email/html/error.ctp
  • src/Template/Plugin/ErrorEmail/Email/text/error.ctp
  • src/Template/Plugin/ErrorEmail/Email/html/exception.ctp
  • src/Template/Plugin/ErrorEmail/Email/text/exception.ctp

Extending/Overriding Core Functions

In order to extend/override core functionality of this plugin you will have to create your own classes which extend this plugin's classes.

Advanced Installation

Create src/Traits/EmailThrowableTrait.php:

<?php
namespace App\Traits;

trait EmailThrowableTrait
{
}

Create src/Error/ErrorHandler.php:

<?php
namespace App\Error;

use App\Traits\EmailThrowableTrait;
use ErrorEmail\Error\ErrorHandler as ErrorEmailErrorHandler;

class ErrorHandler extends ErrorEmailErrorHandler
{
    use EmailThrowableTrait;
}

Create src/Middleware/ErrorHandlerMiddleware.php

<?php
namespace App\Middleware;

use App\Traits\EmailThrowableTrait;
use ErrorEmail\Middleware\ErrorHandlerMiddleware as ErrorEmailErrorHandlerMiddleware;

class ErrorHandlerMiddleware extends ErrorEmailErrorHandlerMiddleware
{
    use EmailThrowableTrait;
}

Now that you have your own classes you will need to update your application to use them.

In your config/Bootstrap.php replace:

use Cake\Error\ErrorHandler; // Or use ErrorEmail\Error\ErrorHandler;

With:

use App\Error\ErrorHandler;

In your src/Application.php replace:

use Cake\Error\Middleware\ErrorHandlerMiddleware; // Or use ErrorEmail\Middleware\ErrorHandlerMiddleware;

With:

use App\Middleware\ErrorHandlerMiddleware;

Adding Arbitrary Logic to Skip Emails

In your src/Traits/EmailThrowableTrait.php add this function:

protected function _appSpecificSkipEmail($throwable)
{
    // Add any logic here to skip emailing throwables that requires more complicated checking
    // than instanceof class provided by plugin config, return true to skip emailing, false to not skip emailing
}

Adding Arbitrary Logic to Skip Throttling

In your src/Traits/EmailThrowableTrait.php add this function:

protected function _appSpecificSkipThrottle($throwable)
{
    // Add any logic here to skip throttling throwables that requires more complicated checking
    // than instanceof class provided by plugin config, return true to skip throttling, false to not skip throttling
}

Overriding Emailing Functionality

In your src/Traits/EmailThrowableTrait.php add this function:

protected function _setupEmail(\Cake\Mailer\Email $email, $throwable)
{
   // Add logic here to pick the email template, layout,
   // set the to address, from address, viewVars, ect.
   // Make sure to return your email object at the end of the function
   // so the plugin can send the email.
   return $email;
}

Bugs and Feedback

http://github.com/ebrigham1/cakephp-error-email/issues

License

Copyright (c) 2017 Ethan Brigham

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

cakephp-error-email's People

Contributors

ebrigham1 avatar smarek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

cakephp-error-email's Issues

Not notify Cake\Http\Exception\HttpException

Hi!
I try your fantastic plugin. The plugin notify to me errors in code but I can't configure notification of type errors like cURL Error (7) Failed to connect to gooooooogle.es port 443: No route to host
Cake\Http\Exception\HttpException

When such an error appears, enter by Cake\Error\Middleware; instead of ErrorEmail\Middleware\ErrorHandlerMiddleware;

How can I configure it to be able to report these errors? Thank you very much

My Cakephp version is 3.7.7

Error after updating to CakePHP 3.8

I am getting the following error:

Fatal error: Uncaught InvalidArgumentException: Unknown email configuration "default". in /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php:2243 Stack trace: #0 /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php(2083): Cake\Mailer\Email->_applyConfig(NULL) #1 /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php(362): Cake\Mailer\Email->setProfile('default') #2 /var/www/x/cakephp/vendor/ebrigham1/cakephp-error-email/src/Traits/EmailThrowableTrait.php(51): Cake\Mailer\Email->__construct('default') #3 /var/www/x/cakephp/vendor/ebrigham1/cakephp-error-email/src/Traits/EmailThrowableTrait.php(37): ErrorEmail\Error\ErrorHandler->_getMailer() #4 /var/www/x/cakephp/vendor/ebrigham1/cakephp-error-email/src/Error/ErrorHandler.php(80): ErrorEmail\Error\ErrorHandler->emailThrowable(Object(Error)) #5 /var/www/x/cakephp/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php(176): ErrorEmail\Error\ErrorHandler->handleException( in /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php on line 2243

Fatal error: Uncaught InvalidArgumentException: Unknown email configuration "default". in /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php:2243 Stack trace: #0 /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php(2083): Cake\Mailer\Email->_applyConfig(NULL) #1 /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php(362): Cake\Mailer\Email->setProfile('default') #2 /var/www/x/cakephp/vendor/ebrigham1/cakephp-error-email/src/Traits/EmailThrowableTrait.php(51): Cake\Mailer\Email->__construct('default') #3 /var/www/x/cakephp/vendor/ebrigham1/cakephp-error-email/src/Traits/EmailThrowableTrait.php(37): ErrorEmail\Error\ErrorHandler->_getMailer() #4 /var/www/x/cakephp/vendor/ebrigham1/cakephp-error-email/src/Error/ErrorHandler.php(80): ErrorEmail\Error\ErrorHandler->emailThrowable(Object(Cake\Error\FatalErrorException)) #5 /var/www/x/cakephp/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php(230): ErrorEmail\Error\Error in /var/www/x/cakephp/vendor/cakephp/cakephp/src/Mailer/Email.php on line 2243

Replace deprecated 'here' attribute

Is it possible to replace deprecated function call in Tempaltes/Email/html/error.ctp and exception.ctp ?

Should be used

$this->request->getAtrribute('here')

instead of currently used

$this->request->here

since this will soon be deprecated.

Thanks.

Async mails

First of all: Very nice documentation and everything. Awesome look and file on first glance!

Too small things though:
It would be good to not have those emails being actually "sent" synchronously.
This can further delay feedback to the user. Ideally those are put somewhere (like a queue), where another task can then collect those jobs and process the actual email sending part.

Another little thing: For a complete system failure this seems to trigger a lot of mails, like millions for a larger visitor count. I can only see an (optional) throttle for a certain blacklist etc, but not for a specific valid "admin mail" for example.
I would probably but a generic "throttle locking" in, that will based on a simple cache value or alike then completely stop sending those alert mails - as the admin sure already got enough of those?
Just some feedback here on the email sending issue.

Replace deprecated methods setTemplate() and setLayout()

Hi,
would it be possilbe to replace deprecated methods

  • setTemplate()
  • setLayout()

in src/Tratis/EmailThrowableTrait.php with

  • $email->viewBuilder()->setTemplate()
  • $email->viewBuilder()->setLayout()

?

As Cake4 is approaching (and methods marked as deprecated are supposed to be removed in v3.8 according to roadmap), maybe there are more than just these two remaining.

Thank you.

Long error message causes "File name too long" issue

[Mon Mar 16 19:12:06.814841 2020] [php7:warn] [pid 23677] [client 1.2.3.4:47120] PHP Warning:  SplFileInfo::openFile(/var/www/html/tmp/cache/error_emails/error_email_error_email_exception_deprecated_exception_request_handler_componentbefore_redirectisdeprecated_thisfunctionalitywillberemovedin400_settheenable_before_redirectoptiontofalsetodisablethiswarningvarwwwhtmlvendorcakephpcakephpsrc_event_event_managerphpline352_youcandisabledeprecationwarningsbysetting_errorerror_levelto_e_a_l_l_e_u_s_e_r_d_e_p_r_e_c_a_t_e_dinyourconfigappphp16384): failed to open stream: File name too long in /var/www/html/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php on line 406, referer: https://censored.domain.com/request/path

There is default limit 255 characters on file-name in usual cases, see https://serverfault.com/a/9548/86062

This particular issue can be tested by enabling deprecation warnings, and using 'emailLevels' => ['exception', 'error', 'warning', 'notice', 'strict', 'deprecated'] config

Therefore process generating the throttle cache file should either trim the cache-key to 255 characters (unpractical and problematic), or generate SHA or other hash from cache-key, to stay in file name length limits (sha256 in hex is 64 characters, that should be safe for all situations)

Not working

I've cloned your plugin inside my plugins dir then I've made configurations like you say in the readme page, but my project don't work it gives me the message:

Fatal error: Uncaught Error: Class 'ErrorEmail\Error\ErrorHandler' not found in /var/www/html/app/config/bootstrap.php:122 Stack trace: #0 /var/www/html/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php(61): require_once() #1 /var/www/html/app/vendor/cakephp/cakephp/src/Http/Server.php(70): Cake\Http\BaseApplication->bootstrap() #2 /var/www/html/app/webroot/index.php(37): Cake\Http\Server->run() #3 {main} thrown in /var/www/html/app/config/bootstrap.php on line 122

I'm loading the plugin in my bootstrap.php
and I've replaced default cakephp error handler by yours
and in my applicationphp error handermidleware I've done the same
in my app.php I've added configuration for default configuration

What may I have done wrong?

EmailThrowableTrait access to context / overriding default algorithms

This is enhancement proposal, solving simple app-specific issue.
If the error is thrown in loop code (ie. generating "Undeffined offset" in loop code), this will generate as many emails, as there are loop iterations.

Currently $cacheKey is determined from throwable class, message and code concatenated and cleaned.

If app is to implement workaround for such situation, it would need to copy relevant code (generating $cacheKey), and for example replace the exception message with filename and line-number, that produced said throwable.

This has 2 possible solutions:

  • Add option ErrorEmail.throttleAlgorithm with numerical values, that identify the algorithm that is used to throttle (this can be expanded later, and each algorithm should be implemented as standalone method in EmailThrowableTrait so it can be overriden for app-specific cases)
  • Update trait interface to protected function _appSpecificSkipThrottle($throwable, $context = []), which would allow passing extra context data to app-specific handler (again, this proposed update can be applied to all _appSpecific* methods), context could in this case include cacheKey, but better would be to extract cacheKey generation to separate function, so it can be overriden ultimately

Second proposed approach, would also help greatly if ErrorHandlerMiddleware.handleException called the trait method _emailThrowable with $request and $response so these could be passed as context in trait methods, or be ultimately accessible from app-specific trait implementation through other methods

This whole proposal is to prevent users of this lib, to blindly copy-paste / override whole functions (such as _throttle or emailThrowable) from current EmailThrowableTrait, to achieve goals similar to described ones, which could result in fatal breaks in future, as soon as the lib code gets updated.

I'm actually thinking about providing both means (extract cacheKey algorithm generation, extract throttle algorithm no.1, and providing context in trait via methods _getRequest and _getResponse), so if you're cool with that, let me know, I'll push relevant changes for you to review.

Composer

Tip:

"cakephp/cakephp": ">=3.3.2 <4.0.0"

can be simplified using carot: ^3.2.2

sending emails on warnings and notice error also

@ebrigham1

Thanks for the nice plugin. It is really good and solved our issues.

We have seen that this plugin only send email on fatal errors. It is not sending emails on "Database Query Errors" and warning and notice errors.

Is there way that we can able to receive those emails also. We want to make our website error free and that we can only able to do if we will going to receive each and every type of emails.

Ignore premature headers emission

Hi, thanks for your wonderful plugin, works really well :-)

One thing, I've not found possible to configure (without subclassing), is to ignore side-WarningExceptions about premature headers emission, when the content (ie. error) is output directly from controller, not from view.

Such will result in 2 additional emails being sent, generated by vendor/cakephp/cakephp/src/Http/ResponseEmitter.php

  • Unable to emit headers. Headers sent in file=/path/to/class/that/printed/output.php line=line-number
  • Cannot modify header information - headers already sent by (output started at /path/to/class/that/printed/output.php:line-number)

These are usually side-effect, not the direct reason, of error occuring.

Would it be possible to filter out these 2 emails, in situation where there are more emails queued about error itself?

Means.

  • scenario 1
    • if controller/model/component/... outputs content, this results only in those 2 emails being sent
    • this is currently handled as it should imo
  • scenario 2
    • if controller/model/component/... produces error which causes subsequently premature content output and 2 additional emails being sent (total 3 or more emails), do not send the 2 emails about error/warning being produced

Cheers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.