• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Error logging in database (and general critique of my code)

#1
[eluser]ilumos[/eluser]
Hi Guys,

I'm building an application which will be used internally at LAN parties and I want to be able to log errors as well as other operations, in a database, for analysis and improvements after an event.

Here's the data I'd like to store:

Code:
mysql> desc lan_logs;
+-----------+----------------------+------+-----+-------------------+----------------+
| Field     | Type                 | Null | Key | Default           | Extra          |
+-----------+----------------------+------+-----+-------------------+----------------+
| log_id    | int(10) unsigned     | NO   | PRI | NULL              | auto_increment |
| user_id   | bigint(20) unsigned  | YES  | MUL | NULL              |                |
| ip        | varchar(15)          | NO   |     | NULL              |                |
| timestamp | timestamp            | NO   |     | CURRENT_TIMESTAMP |                |
| category  | varchar(50)          | NO   |     | NULL              |                |
| severity  | text                 | NO   |     | NULL              |                |
| message   | text                 | NO   |     | NULL              |                |
| data      | text                 | YES  |     | NULL              |                |
| file      | text                 | YES  |     | NULL              |                |
| line      | smallint(5) unsigned | YES  |     | NULL              |                |
+-----------+----------------------+------+-----+-------------------+----------------+

So far I've extended Exceptions.php to log PHP and CI errors, and created a library with a log_action method which allows me to log whatever I want behind the scenes in any of my controllers. I've named the library "usage", as using "log" conflicts with the core - is there any way around this, or can anyone think of any better names?


MY_Exceptions.php
Code:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class MY_Exceptions extends CI_Exceptions
{
function log_exception($severity, $message, $file, $line)
{
  $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
  $this->log_error($severity, $message, $file, $line); // pass to general purpose error logging function
}


function show_404($page = '', $log_error = TRUE)
{
  $heading = '404 Page Not Found';
  $message = 'The page you requested was not found.';

  echo $this->show_error($heading, $message, 'error_404', 404);
  exit;
}

function show_error($heading, $message, $template = 'error_general', $status_code = 500)
{
  set_status_header($status_code);
  $log_message = implode("\r\n", ( ! is_array($message)) ? array($message) : $message);
  $log_message = $heading.': '.$log_message;
  $this->log_error($status_code,'fatal',$log_message); // no way to specify a meaningful error category, or line numbers

  $message = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';

  if (ob_get_level() > $this->ob_level + 1)
  {
   ob_end_flush();
  }
  ob_start();
  include(APPPATH.'errors/'.$template.'.php');
  $buffer = ob_get_contents();
  ob_end_clean();
  return $buffer;
}

function log_error($category, $severity, $message, $file = '', $line = '')
{
  $CI =& get_instance();
  $error_data = array('category' => $category,
       'severity' => $severity,
       'message' => $message,
       'file' => $file,
       'line' => $line,
       );
  $insert = $CI->db->insert('logs', $error_data);
  
  if(!$insert) // fall back to file logging if database insert fails
  {
   $message = 'Severity: '.$severity.'  --&gt; '.$message. ' '.$file.' '.$line;
   log_message('error', $message, TRUE);
  }
}
}

Usage.php (library)
Code:
&lt;?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Usage {

function log($category, $severity, $message, $data = NULL)
{
  $CI =& get_instance();
  $CI->load->helper('session');
  $user_id = get_user_id();
  
  // find out where the log request was called from
  $backtrace = debug_backtrace();
  $file = $backtrace[0]['file'];
  $file = strstr($file,'/application');
  $line = $backtrace[0]['line'];

  if(is_array($data))
  {
   $data = print_r($data,TRUE);
  }
  $insert_data = array(
   'category' => $category,
   'severity' => $severity,
   'message' => $message,
   'data' => $data,
   'user_id' => $user_id,
   'ip' => $_SERVER['REMOTE_ADDR'],
   'file' => $file,
   'line' => $line,
  );
  
  $CI->db->insert('usage', $insert_data);
}
}

<b>I'd prefer not to log errors by hijacking data as it goes through the show_error() method, but it seems like the only way to catch errors that originate from within CodeIgniter's core.</b>

For fatal errors I'd like to do something along these lines:
Code:
$error = 'Unable to retrieve user details from Steam';
$this->usage->log('auth','fatal',$error);
show_error($error);
But of course this would result in two log entries pertaining to the same error - not good.

Is there a better way I could be doing all this? I'm open to general critique of my code too!

Thanks for reading quite a long post!


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.