我有一个Symfony2项目,它将日志写入不同的文件,但我希望它也将日志写入远程数据库(mongodb)。我希望将实际日志文件保留在服务器中作为备份,以防数据库连接出现问题。
问题1: 甚至可以同时将相同的日志保存到两个不同的地方吗?
问题2: 如何将日志保存到mongodb?我不一定需要特定的mongodb指令,但有关如何使用monologger写入远程数据库的一些指导原则。如果可以的话,也欢迎特定于mongodb的说明。 ;)
问题3(可选): 我能以某种方式在日志中获得完整的错误堆栈吗?哪里可以找到Monolog可以实际写入的数据以及如何编写的完整列表?
答案 0 :(得分:1)
有时候有一个非常好的Blogpost用于记录到monolog和doctrine的mysql数据库。我不能再找到它了,所以我只需要在这里添加必要的文件,你就可以调整它了。 整个逻辑在DatabaseHandler中完成,因此您只需更改即可 mysql插入到你的mongodb的处理。 如果有人知道原帖请注释,此代码不是我的。
<强> BacktraceLoggerListener.php 强>
namespace UtilsBundle\EventListener;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
class BacktraceLoggerListener{
private $_logger;
public function __construct(LoggerInterface $logger = null)
{
$this->_logger = $logger;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$this->_logger->addError($event->getException());
}
}
<强> DatabaseHandler.php 强>
namespace UtilsBundle\Logger;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
/**
* Stores to database
*
*/
class DatabaseHandler extends AbstractProcessingHandler{
protected $_container;
/**
* @param string $stream
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($level = Logger::DEBUG, $bubble = true)
{
parent::__construct($level, $bubble);
}
/**
*
* @param type $container
*/
public function setContainer($container)
{
$this->_container = $container;
}
/**
* {@inheritdoc}
*/
protected function write(array $record)
{
// Ensure the doctrine channel is ignored (unless its greater than a warning error), otherwise you will create an infinite loop, as doctrine like to log.. a lot..
if( 'doctrine' == $record['channel'] ) {
if( (int)$record['level'] >= Logger::WARNING ) {
error_log($record['message']);
}
return;
}
// Only log errors greater than a warning
// TODO - you could ideally add this into configuration variable
if( (int)$record['level'] >= Logger::NOTICE ) {
try
{
// Logs are inserted as separate SQL statements, separate to the current transactions that may exist within the entity manager.
$em = $this->_container->get('doctrine')->getManager();
$conn = $em->getConnection();
$created = date('Y-m-d H:i:s');
$serverData = ""; //$record['extra']['server_data'];
$referer = "";
if (isset($_SERVER['HTTP_REFERER'])){
$referer= $_SERVER['HTTP_REFERER'];
}
$stmt = $em->getConnection()->prepare('INSERT INTO system_log(log, level, server_data, modified, created)
VALUES(' . $conn->quote($record['message']) . ', \'' . $record['level'] . '\', ' . $conn->quote($referer) . ', \'' . $created . '\', \'' . $created . '\');');
$stmt->execute();
} catch( \Exception $e ) {
// Fallback to just writing to php error logs if something really bad happens
error_log($record['message']);
error_log($e->getMessage());
}
}
}
}
我们在这里使用了xml,但这可以在 services.yml也是
<强>的services.xml 强>
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="utils.database.logger" class="UtilsBundle\Logger\DatabaseHandler">
<call method="setContainer">
<argument type="service" id="service_container" />
</call>
</service>
<service id="utils.backtrace.logger.listener" class="UtilsBundle\EventListener\BacktraceLoggerListener">
<argument type="service" id="logger" />
<tag name="monolog.logger" channel="backtrace" />
<tag name="kernel.event_listener" event="kernel.exception" method="onKernelException" />
</service>
</services>
最后将处理程序添加到您的monolog配置中 config _ **。yml所以这里用于生产,例如
config_prod.yml
monolog:
handlers:
main:
type: rotating_file
action_level: error
max_files: 10
handler: nested
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
console:
type: console
database:
type: service
level: notice
id: utils.database.logger
channels: ["!translation"]
希望有所帮助
答案 1 :(得分:0)
希望我能帮到你:
问题1 :是的,可能。例如。你可以做smt。像:
$this->logger->pushHandler(new StreamHandler('/path/to/logs/123_info.log', Logger::INFO));
$this->logger->pushHandler(new StreamHandler('/path/to/logs/456_warning.log', Logger::INFO));
因此,如果$this->logger->addInfo("testinfo");
在两个流中都记录了这一点。
问题2 :根据StreamHandler,有一个MongoDBHandler。您应该可以对其进行配置并将其传递给pushHandler方法,或者如果您想在服务中查看它,请查看MongoDBConfiguration。
问题3 : 这应该有所帮助:Configure Monolog
希望有所帮助。