如何在CodeIgniter中存储错误日志到数据库

时间:2013-05-07 07:42:47

标签: codeigniter error-logging

我想通过扩展现有的CI_Log类将系统错误日志存储到数据库。到目前为止,这就是我所做的

class MY_Logger extends CI_Log{
    public function __construct(){
        parent::__construct();
    }

    function write_log($level='error', $msg, $php_error = FALSE){

        $result = parent::write_log($level, $msg, $php_error);
        $ci =& get_instance();
        $ci->load->library('user_agent');
        if ($result == TRUE && strtoupper($level) == 'ERROR') {

            $gmtoffset = 60*60*5;
            $post = array(
                'log_type' => $level,
                'log_message' => $msg,
                'log_php_message' => $php_error,
                'log_ip_origin' => $this->input->ip_address(),
                'log_user_agent' => $this->agent->agent_string(),
                'log_date' => date("Y-m-d H:i:s",time() + $gmtoffset)
            );

            $ci->db->insert('system_log', $post);
        }

        return $result;
    }
}

我在autoload.php和config.php中配置了以下内容

$autoload['libraries'] = array('database', 'session', 'xmlrpc', 'user_agent');
$config['log_threshold'] = 1;

但是当我测试它时,它不会将错误存储到数据库中(尽管它会正确显示和写入日志)

任何人都可以指出我错过了什么吗?

PS:

更改代码以使其扩展CI_Exceptions也不起作用:

class MY_Exceptions extends CI_Exceptions{
    function __construct(){
        parent::__construct();
    }

    function log_exception($severity, $message, $filepath, $line){

        //$result = parent::write_log($level, $msg, $php_error);
        $ci =& get_instance();
        //if ($result == TRUE && strtoupper($level) == 'ERROR') {

            $gmtoffset = 60*60*5;
            $post = array(
                'log_type' => $severity,
                'log_message' => $message,
                'log_php_message' => $line,
                'log_ip_origin' => $ci->input->ip_address(),
                'log_user_agent' => $ci->agent->agent_string(),
                'log_date' => date("Y-m-d H:i:s",time() + $gmtoffset)
            );

            $ci->db->insert('system_log', $post);
        //}
        parent::log_exception($severity, $message, $filepath, $line);
        //return $result;
    }
}

4 个答案:

答案 0 :(得分:0)

我相信我曾经尝试了一段时间并得出结论,不应该在MY_Log中引用CI实例,因为它尚未可用(或者尚未构建)。

答案 1 :(得分:0)

问题正在发生,因为在CI_Controller单例可用之前,正在使用log_message()函数 - 它利用了Log库。

您可能需要添加一个检查以查看CI_Controller类是否仍然可用,如果是,则使用get_instance()函数。然后,当使用$ CI时,您必须首先确保它被正确设置(或者如果您没有使用构造函数来分配$ CI,那么只需在第一个检查的if语句中进行设置)。

您可能正在尝试记录控制器中发生的错误,这意味着数据库功能将在那时可用。对于那些在初始化某些Core文件时出现的早期调试消息,您将只是没有DB日志记录。

答案 2 :(得分:0)

我遇到了类似的加载顺序问题。我的目标是将CI日志重定向到MonoLog并通过电子邮件发送给我。我想使用已经存在的库框架来加载Monolog和SwiftMail,但这是不可用的。

我从CI_Log中的get_config加载了配置设置,但这只包含来自config.php的值(不是来自任何其他配置文件)。我使用get_config函数作为基础来创建另一个函数来加载其他配置文件。然后,这允许我加载我的电子邮件设置。然后我为Monolog和Swiftmail创建了新的加载器。它有点乱,但它确实有效。

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

include_once APPPATH . 'libraries/Swift_Mail/swift_required.php';
require_once APPPATH . 'libraries/common/ClassLoader.php';

use MyApp\Common\ClassLoader,
Monolog\Logger,
Monolog\Handler\RotatingFileHandler,
Monolog\Handler\SwiftMailerHandler,
 Psr\Log\LoggerInterface;

class MY_Log extends CI_Log  {

/** @var \Swift_Mailer  */
private $mailer;

/** @var  $logger LoggerInterface */
protected  $logger;

private $cfg;

public function __construct()
{
    parent::__construct();
    $masterConfig = &get_config(); //This is a config array, not the CI Config object
    $emailConfig = $this->GetConfig('email');
    $this->cfg = array_merge($masterConfig, $emailConfig);

    $this->InitMailer();
    $this->InitLogger();
}

/**
 * There is no exposed CI way to load the email config file, so this allows us to load it.
 * The logic is based on the get_config function in CI.
 * @param $configName
 * @return null
 */
function GetConfig($configName)
{
    $config = null;

    // Is the config file in the environment folder?
    if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/'.$configName.'.php'))
    {
        $file_path = APPPATH.'config/config.php';
    }

    // Fetch the config file
    if ( ! file_exists($file_path))
    {
        exit('The configuration file does not exist.');
    }

    require($file_path);

    // Does the $config array exist in the file?
    if ( ! isset($config) OR ! is_array($config))
    {
        exit('Your config file does not appear to be formatted correctly.');
    }

    return $config;
}

/**
 * This mirrors the init in the SwiftMail Loader.  This is required b/c
 * libraries are not loaded at this point.
 */
protected function InitMailer()
{
    $transport = Swift_SmtpTransport::newInstance
        ($this->cfg['smtp_host'],
            $this->cfg['smtp_port']);

    $transport->setTimeout(20); //Amazon Internal Timeout of 5s, just giving a buffer

    if(array_key_exists('smtp_user',$this->cfg))
    {
        $transport->setUsername($this->cfg['smtp_user']);
    }

    if(array_key_exists('smtp_pass',$this->cfg))
    {
        $transport->setPassword($this->cfg['smtp_pass']);
    }

    if(array_key_exists('smtp_crypto',$this->cfg))
    {
        $transport->setEncryption($this->cfg['smtp_crypto']);
    }

    /** @var  $mailer Swift_Mailer*/
    $this->mailer = Swift_Mailer::newInstance($transport);
}

/**
 * Setup monolog.
 */
protected function InitLogger()
{
    $loader = new ClassLoader("Psr", APPPATH . 'libraries');
    $loader->register();

    $loader = new ClassLoader("Monolog", APPPATH . 'libraries');
    $loader->register();

    $logLevel = Logger::ERROR;

    /* CI Error levels
     *  |   0 = Disables logging, Error logging TURNED OFF
        |   1 = Error Messages (including PHP errors)
        |   2 = Debug Messages
        |   3 = Informational Messages
        |   4 = All Messages
     */

    switch($this->cfg['log_threshold'])
    {
        case 0:
            $logLevel = Logger::ERROR; //We still want errors.
            break;
        case 1:
            $logLevel = Logger::INFO;
            break;
        case 2:
            $logLevel = Logger::DEBUG;
            break;
        case 3:
            $logLevel = Logger::INFO;
            break;
        case 4:
            $logLevel = Logger::DEBUG;
            break;
    }

    /** @var  $message Swift_Message*/
    $message = Swift_Message::newInstance('MyApp Error - '.ENVIRONMENT)
        ->setFrom($this->cfg['FROM_ADDR'])
        ->setTo($this->cfg['ERROR_ADDR']);

    $swiftMailHandler = new SwiftMailerHandler($this->mailer, $message, Logger::ERROR);


    $this->logger = new Logger('myapp');
    $this->logger->pushHandler(new RotatingFileHandler(APPPATH.'logs/myapp.log', 0, $logLevel, true, 0666));
    $this->logger->pushHandler($swiftMailHandler);
}


public function write_log($level = 'error', $msg, $php_error = FALSE)
{
    parent::write_log($level, $msg, $php_error);

    if($level === 'error')
    {
        $this->logger->error($msg);
    }
    elseif($level === 'debug')
    {
        $this->logger->debug($msg);
    }
    else
    {
        $this->logger->info($msg);
    }
}

}

答案 3 :(得分:0)

@Jeremy在您的评论之一中,您提到记录器类存储在 libraries 文件夹中。而是应将其放置在 core 文件夹下,名称为MY_Log.php。有关更多详细信息,请参见以下链接:

https://codeigniter.com/user_guide/general/core_classes.html#extending-core-class

唯一的问题是文件命名约定并将其放置在错误的文件夹中。至于您的代码,我已经在最后对其进行了测试,并且可以正常工作。我知道这是一个老问题,但是知道相同的解决方案,所以与大家分享。