我想通过扩展现有的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;
}
}
答案 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
唯一的问题是文件命名约定并将其放置在错误的文件夹中。至于您的代码,我已经在最后对其进行了测试,并且可以正常工作。我知道这是一个老问题,但是知道相同的解决方案,所以与大家分享。