monolog-bundle icon indicating copy to clipboard operation
monolog-bundle copied to clipboard

Cannot override handlers for test environment

Open Koitus01 opened this issue 10 months ago • 2 comments

"symfony/monolog-bundle": "^3.10" "php": ">=8.2"

I have the monolog.yaml for my dev, stage and prod environments:

monolog:
    handlers:
        console:
            type: stream
            path: 'php://stdout'
            level: info
            channels: [ 'console' ]
        errors:
            type: fingers_crossed
            action_level: warning
            excluded_http_codes: [ 404 ]
            handler: errors_nested
        errors_nested:
            type: gelf
            level: warning
            formatter: Monolog\Formatter\GelfMessageFormatter
            publisher: Gelf\Publisher
            channels: [ '!app' ]
        manual:
            type: gelf
            level: debug
            formatter: Monolog\Formatter\GelfMessageFormatter
            publisher: Gelf\Publisher
            channels: [ 'app' ]

which sends logs in Graylog. But i don't want to use graylog in test environment, so i tried few versions of test/monolog.yaml:

monolog:
    handlers:
        errors:
            type: stream
            path: 'php://stdout'
            level: warning
            channels: ['!app']
        manual:
            type: stream
            path: 'php://stdout'
            level: debug
            channels: [ 'app' ]
monolog:
    handlers:
        errors:
            type: test
        manual:
            type: test
monolog:
    handlers:
        errors:
            type: null
        manual:
            type: null
        main:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
monolog:
    handlers:
        errors:
            type: null
            handler: null
        manual:
            type: null
            handler: null
        main:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug

but all of this configs give me an error:

In BaseNode.php line 407:
                                                                                                                                                        
  [Symfony\Component\Config\Definition\Exception\InvalidConfigurationException]                                                                         
  Invalid configuration for path "monolog.handlers.errors": You can only use excluded_http_codes/excluded_404s with a FingersCrossedHandler definition  
                                                                                                                                                        

Exception trace:
  at /application/vendor/symfony/config/Definition/BaseNode.php:407
 Symfony\Component\Config\Definition\BaseNode->finalize() at /application/vendor/symfony/config/Definition/PrototypedArrayNode.php:165
 Symfony\Component\Config\Definition\PrototypedArrayNode->finalizeValue() at /application/vendor/symfony/config/Definition/BaseNode.php:393
 Symfony\Component\Config\Definition\BaseNode->finalize() at /application/vendor/symfony/config/Definition/ArrayNode.php:232
 Symfony\Component\Config\Definition\ArrayNode->finalizeValue() at /application/vendor/symfony/config/Definition/BaseNode.php:393
 Symfony\Component\Config\Definition\BaseNode->finalize() at /application/vendor/symfony/config/Definition/Processor.php:36
 Symfony\Component\Config\Definition\Processor->process() at /application/vendor/symfony/config/Definition/Processor.php:46
 Symfony\Component\Config\Definition\Processor->processConfiguration() at /application/vendor/symfony/dependency-injection/Extension/Extension.php:109
 Symfony\Component\DependencyInjection\Extension\Extension->processConfiguration() at /application/vendor/symfony/monolog-bundle/DependencyInjection/MonologExtension.php:62
 Symfony\Bundle\MonologBundle\DependencyInjection\MonologExtension->load() at /application/vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php:81
 Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass->process() at /application/vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php:40
 Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass->process() at /application/vendor/symfony/dependency-injection/Compiler/Compiler.php:73
 Symfony\Component\DependencyInjection\Compiler\Compiler->compile() at /application/vendor/symfony/dependency-injection/ContainerBuilder.php:752
 Symfony\Component\DependencyInjection\ContainerBuilder->compile() at /application/vendor/symfony/http-kernel/Kernel.php:495
 Symfony\Component\HttpKernel\Kernel->initializeContainer() at /application/vendor/symfony/http-kernel/Kernel.php:740
 Symfony\Component\HttpKernel\Kernel->preBoot() at /application/vendor/symfony/http-kernel/Kernel.php:120
 Symfony\Component\HttpKernel\Kernel->boot() at /application/vendor/codeception/module-symfony/src/Codeception/Module/Symfony.php:214
 Codeception\Module\Symfony->_initialize() at /application/vendor/codeception/codeception/src/Codeception/SuiteManager.php:72
 Codeception\SuiteManager->initialize() at /application/vendor/codeception/codeception/src/Codeception/Codecept.php:256
 Codeception\Codecept->runSuite() at /application/vendor/codeception/codeception/src/Codeception/Codecept.php:216
 Codeception\Codecept->run() at /application/vendor/codeception/codeception/src/Codeception/Command/Run.php:435
 Codeception\Command\Run->execute() at /application/vendor/symfony/console/Command/Command.php:279
 Symfony\Component\Console\Command\Command->run() at /application/vendor/symfony/console/Application.php:1029
 Symfony\Component\Console\Application->doRunCommand() at /application/vendor/symfony/console/Application.php:316
 Symfony\Component\Console\Application->doRun() at /application/vendor/symfony/console/Application.php:167
 Symfony\Component\Console\Application->run() at /application/vendor/codeception/codeception/src/Codeception/Application.php:112
 Codeception\Application->run() at /application/vendor/codeception/codeception/app.php:45
 {closure}() at /application/vendor/codeception/codeception/app.php:46
 require() at /application/vendor/codeception/codeception/codecept:7
 include() at /application/vendor/bin/codecept:119

How to properly override monolog.yaml handlers in test or other environments?

Koitus01 avatar Feb 06 '25 11:02 Koitus01

Maybe you should use the when@ syntax in your monolog.yaml ?

Example :

when@dev:
    monolog:
        handlers:
            main:

And :

when@prod:
    monolog:
        handlers:
            main:

micter59 avatar Mar 05 '25 09:03 micter59

I ran into the same issue using this configuration. I hope the following may offer a reproducer

file config/packages/monolog.yaml :

monolog:
    channels:
        - "deprecation"

    handlers:
        # default handlers
        main:
            type: fingers_crossed
            action_level: error
            handler: nested
            excluded_http_codes: [404, 405]
            buffer_size: 50 # How many messages should be saved? Prevent memory leaks
        nested:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
        console:
            type: console
            process_psr_3_messages: false
            channels: [ "!event", "!doctrine" ]
        deprecation:
            type: rotating_file
            path: "%kernel.logs_dir%/deprecation.log"
            level: debug
            max_files: 12
            channels: [ "deprecation" ]

when@dev:
    monolog:
        handlers:
            main:
                type: stream
                path: "%kernel.logs_dir%/%kernel.environment%.log"
                level: debug
                channels: ["!event"]
            # uncomment to get logging in your browser
            # you may have to allow bigger header sizes in your Web server configuration
            #firephp:
            #    type: firephp
            #    level: info
            #chromephp:
            #    type: chromephp
            #    level: info
            console:
                type: console
                process_psr_3_messages: false
                channels: ["!event", "!doctrine", "!console"]

when@test:
    monolog:
        handlers:
            main:
                type: fingers_crossed
                action_level: error
                handler: nested
                excluded_http_codes: [404, 405]
                channels: ["!event"]
            nested:
                type: stream
                path: "%kernel.logs_dir%/%kernel.environment%.log"
                level: debug

when@prod:
    monolog:
        handlers:
            main:
                type: fingers_crossed
                action_level: error
                handler: nested
                excluded_http_codes: [404, 405]
                buffer_size: 50 # How many messages should be saved? Prevent memory leaks
            nested:
                type: stream
                path: php://stderr
                level: debug
                formatter: monolog.formatter.json
            console:
                type: console
                process_psr_3_messages: false
                channels: ["!event", "!doctrine"]
            deprecation:
                type: stream
                channels: [deprecation]
                path: php://stderr
                formatter: monolog.formatter.json

Versions :

symfony/monolog-bridge : 6.4.13 symfony/monolog-bundle : 3.10.0 monolog/monolog : 3.9.0

Tests done

  1. Commenting excluded_http_codes: [404, 405] in "global" configuration suppresses the error.
  2. Commenting when@... configurations suppresses the error.
  3. Matching when@test main + nested handler on when@dev main handler suppresses the error.

ktherage avatar May 13 '25 12:05 ktherage

The issue is that the configs are deep merged. This can be disabled by calling performNoDeepMerging() but that would be a breaking change and I don't know any way to deprecate the current behavior and force to repeat all the parameters of each handler.

I don't think this can be solved by the bundle itself.

GromNaN avatar Oct 30 '25 16:10 GromNaN

I think we should be less strict about forbidding settings that don't apply to a given handler type, to make it easier to change the handler type when merging config.

stof avatar Oct 30 '25 17:10 stof

It's possible to unset the value with excluded_http_codes: false But there is a bug in the transformation: https://github.com/symfony/monolog-bundle/pull/556

GromNaN avatar Oct 30 '25 19:10 GromNaN