# Possible to dynamically change the ErrorHandler's logger? (Slim 4)

**URL:** <https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903>\
**Category:** Questions\
**Created:** [July 27, 2021, 7:06pm UTC](https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903 "2021-07-27T19:06:04Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![merricat](https://avatars.discourse-cdn.com/v4/letter/m/8dc957/32.png) [@merricat](https://discourse.slimframework.com/u/merricat)\
**Post date:** [July 27, 2021, 7:06pm UTC](https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903/1 "2021-07-27T19:06:04Z")

</div>

Here’s the setup (and maybe someone can offer an alternative to my current system):

**Application Middleware** (added in this order, so executed in reverse):

1. ErrorMiddleware (w/ custom ErrorHandler)
2. RoutingMiddleware
3. CustomMiddleware (determines api version and therefore which directory/files to `include`)

**Reasoning** :  
I’m adding RoutingMW after the ErrorMW so when they run in reverse I have access to any routing info during my error middleware/handler. Also, I don’t know why I can’t put my CustomMW first and therefore run it last (it throws a status 500, and I can’t seem to debug it).

When I set my ErrorMW, I also create my custom ErrorHandler and pass it to the ErrorMW as the default handler. I want the ErrorHandler to have a logger, so I set the DI container’s logger to write into my “lastest api version” directory (say, `/logs/v2.0/api-log`), and inject that into the ErrorHandler. When the app runs and finally determines the right API version, I overwrite the DI container’s logger with the chosen API version for the log file directory, and then inject that logger in my various controllers as needed. If the user is running an old app and needs an older API like `1.0`, the application will log non-errors to the correct `/logs/v1.0/api-log`, but the ErrorHandler will still reference the old Logger I gave it during the application Middleware setup (`/logs/v2.0/api-log`), so any errors are written there instead.

**Is there a way, during the application, to change the custom ErrorHandler’s logger and set it to the correct `1.0` path?**

Hope that made sense,  
Thanks!

---

<div class="post-metadata">

**Author:** ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)\
**Post date:** [July 27, 2021, 9:03pm UTC](https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903/2 "2021-07-27T21:03:39Z")

</div>

Note that in Slim the middleware stack is LIFO (last in, first out). The middleware you add last is executed first. So the order is “reversed”.

I think the ErrorMiddleware should be the last middleware in the stack to catch all exceptions of your application. So the Routing middleware should be added before the ErrorMiddleware. And the CustomMiddleware should be added before the Routing middleware.

Example:

```php
$app->add(CustomMiddlware::class);
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);

```

When you want to configure a custom Logger for the ErrorMiddleware you may add a DI container definition instead and pass your custom logger there.

Add a new container defintion:

```php
use Psr\Container\ContainerInterface;
use Slim\App;
use Slim\Middleware\ErrorMiddleware;
// ...

return [
    App::class => function (ContainerInterface $container) {
        AppFactory::setContainer($container);
    
        return AppFactory::create();
    },

    ErrorMiddleware::class => function (ContainerInterface $container) {
        $settings = $container->get('settings')['error'];
        $app = $container->get(App::class);

        // Create a custom logger here
        $logger = ...;

        $errorMiddleware = new ErrorMiddleware(
            $app->getCallableResolver(),
            $app->getResponseFactory(),
            (bool)$settings['display_error_details'],
            (bool)$settings['log_errors'],
            (bool)$settings['log_error_details'],
            $logger
        );

        return $errorMiddleware;
    },
];

```

Then replace `addErrorMiddleware` with the ErrorMiddleware class to let the DI container inject the ErrorMiddleware:

```php
use Slim\Middleware\ErrorMiddleware;

// ...
$app->add(ErrorMiddleware::class);

```

PS: You also need to fetch the App instance from the DI container as well then.

```php
// Create App instance
$app = $container->get(App::class);

// ...

$app->run();

```

---

<div class="post-metadata">

**Author:** ![merricat](https://avatars.discourse-cdn.com/v4/letter/m/8dc957/32.png) [@merricat](https://discourse.slimframework.com/u/merricat)\
**Post date:** [July 27, 2021, 10:45pm UTC](https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903/3 "2021-07-27T22:45:58Z")

</div>

Hi there, thanks for the reply.  
I’m not understanding your first block of code. I usually do:

```auto
container->set(MyClass::class, function($container){
    //...
});

```

Also, I don’t understand… why do you add the App to the container? Also, I am aware of the order of execution of the middleware, and that’s why I specifically stated the reasoning behind the error middleware not being last: I want the routing info if an exception is thrown, and that data would not be available yet. Finally, I already said that I tried putting my custom middleware first, but I can’t figure out what the problem is yet.

Your solution doesn’t work for me because the settings needed to create the logger (namely, the api version, which is used to build the path where the logs are written to) are determined after all middleware get executed.

Anyway, I already figured out a solution that works for me.

```auto
$myErrorHandler = new MyErrorHandler($app->getCallableResolver(), $app->getResponseFactory(), null, $container);

$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($myErrorHandler);

```

I basically inject, in MyErrorHandler, the `$container` rather than my “old logger”. This way when MyErrorHandler’s `__invoke()` is called, it can dynamically retrieve the correct logger by calling `$container->get('my_correct_api_version_logger')`

I don’t know, this might be a silly approach (I’m cringing at the thought of passing the `$container` to the ErrorHandler), but it’s working at least. However, this is making me rethink my need for a dynamic logger. Maybe logging separate api versions into one file isn’t such a bad idea. Thoughts?

---

<div class="post-metadata">

**Author:** ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)\
**Post date:** [July 28, 2021, 5:55am UTC](https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903/4 "2021-07-28T05:55:56Z")

</div>

Yes, passing the container should be avoided when possible.  
Another approach would be a routing group for each API version and then add a custom LoggerVersion1Middleware and LoggerVersion2Middleware to each of this routing group.  
The LoggerVersionXMiddleware then would configure the Slim ErrorMiddleware with a custom ErrorHandler. `$errorMiddleware->setDefaultErrorHandler($myErrorHandler);`.

---

<div class="post-metadata">

**Author:** ![dafriend](https://avatars.discourse-cdn.com/v4/letter/d/da6949/32.png) [@dafriend](https://discourse.slimframework.com/u/dafriend)\
**Post date:** [July 28, 2021, 2:26pm UTC](https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903/5 "2021-07-28T14:26:43Z")

</div>

> [@merricat](#):
>
> …the reasoning behind the error middleware not being last: I want the routing info if an exception is thrown, and that data would not be available yet.

The error middleware, once instantiated, will handle errors for the entire lifecycle of the app. It’s best if it’s up and running as soon as possible. Assuming the request object is available where an exception occurs you can access a RouteContext to provide routing info.

---

<div class="post-metadata">

**Author:** ![merricat](https://avatars.discourse-cdn.com/v4/letter/m/8dc957/32.png) [@merricat](https://discourse.slimframework.com/u/merricat)\
**Post date:** [July 28, 2021, 4:34pm UTC](https://discourse.slimframework.com/t/possible-to-dynamically-change-the-errorhandlers-logger-slim-4/4903/6 "2021-07-28T16:34:33Z")

</div>

> [@odan](#):
>
> The LoggerVersionXMiddleware then would configure the Slim ErrorMiddleware with a custom ErrorHandler. `$errorMiddleware->setDefaultErrorHandler($myErrorHandler);` .

@odan How do I get access to the `$errorMiddleware` /its errorHandler from a route group? That was, in essence, the root of my original issue – I couldn’t change the errorHandler once I set it up in the application middleware.

Thanks again for the suggestions!!

By the way: this is the error I get when I do your suggested order of application middleware (custom, routing, error - added in that order)

```auto
404 Not Found
The application could not run because of the following error:

Type: Slim\Exception\HttpNotFoundException
Code: 404
Message: Not found.
File: [...]/composer/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php
Line: 91

```

Commenting out the middle one (Routing, aka `$app->addRoutingMiddleware()`), or swapping it with my custom middleware, makes my request go through properly.

I just read this in the docs:

> If you were using `determineRouteBeforeAppMiddleware`, you need to add the Middleware\RoutingMiddleware middleware to your application just before your call run() to maintain the previous behaviour.

But I don’t even know what `determineRouteBeforeAppMiddleware` is, I’ve never seen such a setting, so I’m confused.

@dafriend Moving the error middleware last, I get the following error when manually throwing an exception in my first GET route: `Cannot create RouteContext before routing has been completed`. My custom error handler simply tries to to access `\Slim\Routing\RouteContext::fromRequest($request)`, but it fails with that error. That’s why I ended up placing the Routing middleware last.

P.S. I just realized that I had a weird setup: my actual routes were technically _inside_ my custom application middleware. This middleware would create a `$api_version` based on user input, and then I would `require_once "path/to/{$api_version}/api/routes.php"`. To try something, I moved out the `require_once "[...]/routes.php"` and put it after the three application middleware and before the `$app->run()`, and then I finally stopped getting the 404 error above when placing my custom application middleware before the routing.  
So, I think I’m doing my versioning routing wrong. How can I not hardcode a specific api version on my client app, say v1, yet dynamically choose which `routes.php` file to include? I tried using the DI container to store the chosen `$api_version` (when inside my custom application middleware), and then read it like so `$this->getContainer()->get('app_version')` inside a route group, but that doesn’t work inside a group.  
Any suggestions on the best way to version or simply to include the right version of my routes?

I feel like this post went a bit off-topic, but I think it’s revealing the deeper source of my issue. Thanks! 😃
