bugsnag / bugsnag-laravel

BugSnag notifier for the Laravel PHP framework. Monitor and report Laravel errors.
https://docs.bugsnag.com/platforms/php/laravel/
MIT License
876 stars 129 forks source link

Feature: Defer service provider #542

Open henzeb opened 3 days ago

henzeb commented 3 days ago

Description

In theory, Bugsnag laravel should work with Laravel Zero. However, the register provider flow of laravel zero, currently prevents us from using bugsnag. That flow is as follows:

  1. Foundation providers are registered. This includes user configured providers
  2. Component service providers are registered. These include the log service provider.

As a result, "Target class [log] does not exist. " error is thrown. You can't prepend the log service provider in the configuration file or anywhere else, as the component service provider simply overwrites the current binding. this doesn't give any errors when using Log facade, but doesn't log anything to bugsnag either.

Describe the solution you'd like two things can be done:

  1. The current service provider becomes a deferred service provider. This would give us some performance win as we do not use the Log facade everywhere all at once. This might be a breaking change, but I am not sure.
  2. A Laravel Zero specific provider that is deferred and extends the main service provider.

Describe alternatives you've considered I've posted a similar bug report at the Laravel Zero github. Maybe there a solution may come up. for instance, a way to prepend providers. Although they already have the solution, which is the deferred service provider.

henzeb commented 14 hours ago

I thought I give it ago and this is what works for me. There may be some issues conserning Oom, as I haven't fully tested that yet, but this seems promising:

class DeferredBugsnagProvider extends BugsnagServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->bind(
            'request',
            fn() => new class () {
                public function server(): string
                {
                    return config('app.servername');
                }
            }
        );
        parent::register();
    }

    public function provides(): array
    {
        return [
            'request',
            'bugsnag',
            'bugsnag.tracker',
            'bugsnag.logger',
            'bugsnag.multi'
        ];
    }
}

You probably wonder what request is doing there: request usually resolves to Illuminate\Http\Request, but Laravel Zero doesn't know this class as it is a console application. Since bugsnag only needs the server method, I added in an anonymous class that has one method. It can return anything you want.

GrahamCampbell commented 14 hours ago

Deferring Bugsnag is not a good idea, because it needs to be loaded early in the bootstrapping process, to enable it to intercept crashes during framework boot.

henzeb commented 13 hours ago

Deferring Bugsnag is not a good idea, because it needs to be loaded early in the bootstrapping process, to enable it to intercept crashes during framework boot.

I agree, but Laravel Zero won't let us do that in the current implementation. the Log component is bound AFTER the providers that are configured by the user. Let's hope this is a temporary workaround.