Jump to content

Logging PHP errors with set_error_handler()


sKunKbad

Recommended Posts

So, I'd like to log my PHP errors on my production environment, and a cron will send them to me via email. I used to just send them instantly to myself with email, but had a bad experience where a loop sent me about 4000 emails. I can use set_error_handler() returning FALSE so that PHP stops execution when necessary, and I don't have to call die(). In the production environment display_errors is set to 0, and so is error_reporting(). This seems to work fine, but I'm wondering if there are any unseen side effects of what I'm doing. Please take a look:

<?php

class Tvsc_error_handler {

	public $error_count = 0;

	public $error_limit = 25;

	public $error_type = '';

	// -----------------------------------------------------------------------
	
	public function set_tvsc_error_handler()
	{
		if( ENVIRONMENT == 'production' )
		{
			set_error_handler( [ $this, 'production_errors'], E_ALL & ~E_DEPRECATED );
		}
	}

	// -----------------------------------------------------------------------
	
	public function production_errors( $e_number, $e_message, $e_file, $e_line, $e_vars )
	{
		$this->error_count++;

		$this->set_error_type( $e_number );

		// Start log entry with basic error info
		$log_entry = '#---' . PHP_EOL . 
			'PHP ' . $this->error_type . ' #' . $e_number . ' - Date/Time: ' . date('n/j/Y H:i:s') . PHP_EOL .
			'File: ' . $e_file . PHP_EOL .
			'Line: ' . $e_line . PHP_EOL .
			'Message: ' . $e_message . PHP_EOL;

		// Include post vars in log entry
		if( isset( $_POST ) && ! empty( $_POST ) )
		{
			$log_entry .= 'POST vars:' . PHP_EOL;

			foreach( $_POST as $k => $v )
			{
				$log_entry .= "\t" . $k . ' = ' . $v . PHP_EOL;
			}
		}

		// Include request headers in log entry
		if( $request_headers = apache_request_headers() )
		{
			$log_entry .= 'Request headers:' . PHP_EOL;

			foreach( $request_headers as $k => $v )
			{
				$log_entry .= "\t" . $k . ' = ' . $v . PHP_EOL;
			}
		}

		// Include request URI in log entry
		$log_entry .= 'Request URI: ' . $_SERVER['REQUEST_URI'] . PHP_EOL;

		// Include error count in log entry
		$log_entry .= 'Error Count: ' . $this->error_count . PHP_EOL;

		// Finish log entry
		$log_entry .= '#--' . PHP_EOL;

		// Second param (3) says to store error in specified log file
		error_log( $log_entry, 3, APPPATH . 'logs/php_errors/php_errors.log' );

		// If too many errors of any type, die()
		if( $this->error_count > $this->error_limit )
		{
			die( '<span style="color:red;">
				A system error occurred. We apologize for the inconvenience.
			</span><br />
			<span style="font-size:50%;">
				ERRORS > ' . $this->error_limit . '
			</span>');
		}

		// Continue to execute PHP internal error handler
		return FALSE;
	}

	// -----------------------------------------------------------------------

	private function set_error_type( $e_number )
	{
		switch( $e_number )
		{
			case E_PARSE:
			case E_ERROR:
			case E_CORE_ERROR:
			case E_COMPILE_ERROR:
			case E_USER_ERROR:
				$this->error_type = 'FATAL ERROR';
				break;
			case E_WARNING:
			case E_USER_WARNING:
			case E_COMPILE_WARNING:
			case E_RECOVERABLE_ERROR:
				$this->error_type = 'WARNING';
				break;
			case E_NOTICE:
			case E_USER_NOTICE:
				$this->error_type = 'NOTICE';
				break;
			case E_STRICT:
				$this->error_type = 'STRICT';
				break;
			case E_DEPRECATED:
			case E_USER_DEPRECATED:
				$this->error_type = 'DEPRECATED';
				break;
			default:
				$this->error_type = 'UNKNOWN ERROR TYPE';
				break;
		}
	}

	// -----------------------------------------------------------------------

}

Might there be a better way?

Link to comment
Share on other sites

Have error_reporting ON in both environments

 

In development, have display_errors ON

In production, have log_errors ON instead.

 

I understand that it would be better to allow PHP to log it's own errors, and I could even specify the location of a custom error log, but I like having the extra info in the log, such as request URI, headers, post data, etc.

 

You suggest to have error_reporting on in both environments, but interestingly the errors are getting logged even when it is set to 0 in production.

Link to comment
Share on other sites

Setting a custom error handler overrides the error_reporting value.

 

Note that custom handlers installed at runtime generally cannot catch errors which happen at compile time or during the startup sequence (syntax errors, extension issues etc.). You should set the handler in an auto-prepended script so that it's executed before the actual application.

 

Also note that there are plenty of professional logging libraries like Monolog. Before you write your own, check if they already do what you want.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.