Как настроить Monolog для хранения логов в MongoDB с помощью Symfony2 и Doctrine

Можно ли получить полный пример того, как можно настроить Monolog для хранения своих журналов в MongoDB с использованием Symfony 2.6 и Doctrine 2?


person Francesco Casula    schedule 08.05.2015    source источник


Ответы (1)


Полная конфигурация

/app/parameters.yml

mongodb_server: "mongodb://localhost:27017"
mongodb_username: "vagrant"
mongodb_password: "password"
mongodb_database: "testdb"

/app/config.yml

# Doctrine2 MongoDB Bundle
# http://symfony.com/doc/current/bundles/DoctrineMongoDBBundle/index.html
doctrine_mongodb:
    default_database: %mongodb_database%
    connections:
    default:
        server: %mongodb_server%
        options:
            password: %mongodb_password%
            username: %mongodb_username%
            db: %mongodb_database%
            connect: true
    log:
        server: %mongodb_server%
        options:
            password: %mongodb_password%
            username: %mongodb_username%
            db: %mongodb_database%
            connect: true
    document_managers:
    default:
        auto_mapping: true
    log:
        auto_mapping: false
        logging: false

/app/services.yml

mongolog:
    class: Doctrine\MongoDB\Connection
    factory_service: doctrine_mongodb.odm.log_connection
    factory_method: getMongoClient

/app/config_dev.yml

В этом примере я решил хранить все (уровень debug), как всегда, в dev.log и только ошибки, предупреждения и уведомления на монго.

monolog:
    handlers:
    main:
        type:   stream
        path:   "%kernel.logs_dir%/%kernel.environment%.log"
        level:  debug
    console:
        type:   console
        bubble: false
        verbosity_levels:
            VERBOSITY_VERBOSE: INFO
            VERBOSITY_VERY_VERBOSE: DEBUG
        channels: ["!doctrine"]
    console_very_verbose:
        type:   console
        bubble: false
        verbosity_levels:
            VERBOSITY_VERBOSE: NOTICE
            VERBOSITY_VERY_VERBOSE: NOTICE
            VERBOSITY_DEBUG: DEBUG
        channels: ["doctrine"]
    mongo:
        type:   mongo
        level:  notice # change as desired
        mongo:
            id: mongolog
            database: %mongodb_database%
            collection: logs

/app/config_prod.yml

monolog:
    handlers:
    main:
        type:         fingers_crossed
        action_level: error
        handler:      mongo
    nested:
        type:  stream
        path:  "%kernel.logs_dir%/%kernel.environment%.log"
        level: debug
    console:
        type:  console
    mongo:
        type: mongo
        level: notice
        mongo:
            id: mongolog
            database: %mongodb_database%
            collection: logs

Теперь давайте активируем уведомление PHP и проверим, будет ли оно правильно храниться в MongoDB :-)

<?php trigger_error('hello world!', E_USER_NOTICE);

Добавление заголовков HTTP-запроса в запись Monolog

/app/services.yml

kernel.listener.exception_listener:
    class: AppBundle\EventListener\ExceptionListener
    arguments:
        - @logger
    tags:
        - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

AppBundle\EventListener\ExceptionListener

<?php

namespace AppBundle\EventListener;

use Monolog\Handler\MongoDBHandler;
use Symfony\Bridge\Monolog\Logger;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

/**
 * Class ExceptionListener
 * @package AppBundle\EventListener
 * @author Francesco Casula <[email protected]>
 */
class ExceptionListener extends ExceptionHandler
{
    /**
     * @var Logger
     */
    private $logger;

    /**
     * @param Logger $logger
     */
    public function __construct(Logger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @return Logger
     */
    public function getLogger()
    {
        return $this->logger;
    }

    /**
     * @param GetResponseForExceptionEvent $event
     */
    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        foreach ($this->getLogger()->getHandlers() as $handler) {
            if ($handler instanceof MongoDBHandler) {
                $handler->pushProcessor(function (array $record) use ($event) {
                    $record['extra']['headers'] = $event->getRequest()->headers->all();
                    return $record;
                });

                break;
            }
        }
    }
}
person Francesco Casula    schedule 08.05.2015
comment
Франческо, это действительно круто и, насколько я могу сказать, это работает. Однако один вопрос. Как подготовить эти данные? В вашем учебнике/конфигурации нет объекта Document Object, поэтому можно ли читать из MongoDB с помощью Doctrine без этих объектов? Только сырые данные? Как? - person pawel.kalisz; 16.04.2016
comment
Привет, @pawel.kalisz, мы уже давно используем этот метод в производстве. Мы храним в основном исключение со всей трассировкой стека, и мы обнаружили, что MongoChef является очень хорошим интерфейсом для подключения к нашему экземпляру MongoDB и просмотра журналов. Иногда мы также запускаем запросы через оболочку Mongo (командная строка). В этом случае просто убедитесь, что вы сузили не только набор записей, но и его проекцию (второй параметр db.collection.find, см. docs.mongodb.org/manual/reference/method/db.collection.find) - person Francesco Casula; 16.04.2016
comment
Если вы хотите использовать только PHP, я думаю, вы все равно можете использовать Doctrine или просто классы PHP Mongo. - person Francesco Casula; 16.04.2016