yii-debug icon indicating copy to clipboard operation
yii-debug copied to clipboard

Concept of Debug Activators

Open xepozz opened this issue 1 year ago • 3 comments

There are a few places that can be redesigned to be scalable:

  • https://github.com/yiisoft/yii-debug/blob/cd4fe68e20980a29c3bd305c726fe5c07bb8995b/src/Debugger.php#L42
  • https://github.com/yiisoft/yii-debug/blob/cd4fe68e20980a29c3bd305c726fe5c07bb8995b/src/Debugger.php#L47

There are checks that disable (not enable) collectors' startup. Thinking global it could be a list of classes/closures that can activate the Debugger.

It may be useful in production, when you want to enable debug only for your network/list of users/state of application/any logic.

xepozz avatar Sep 08 '24 17:09 xepozz

That would a pretty big list, wouldn't?

samdark avatar Sep 09 '24 10:09 samdark

Possible (de)activators:

  • command name / route name / request path
  • user id
  • user role
  • ip subnet
  • secure cookie
  • session flags
  • http header
  • query parameter
  • user callback

I think 1 or two will be used by default, like command/route names + ip subnet mask

xepozz avatar Sep 09 '24 14:09 xepozz

What do you think of such concept?

interface ActivatorInterface // is there a better name?
{
    // null = no idea, true = activate, false = deactivate
    public function isActive($event): ?bool;
}

final class CompositeActivator implements 
{
    public function __construct(private array $activators)
    {}

    public function isActive($event): ?bool
    {
        foreach ($this->activators as $activator) {
            // how to deal with true-false situation?
            $result = $activator->isActive();
            if (is_bool($result)) {
                return $result;
            }
        }
        return false;
    }
}

final class IgnoreRequestActivator implements ActivatorInterface
{
    public function __construct(
        private array $urls = []
    )
    {
    }

    public function isActive($event): ?bool
    {
        if (!$event instanceof BeforeRequest) {
            return null;
        }

        return $this->isRequestActive($event->getRequest());

}


final class IgnoreCommandActivator implements ActivatorInterface
{
    public function __construct(
        private array $commands = []
    )
    {
    }

    public function isActive($event): ?bool
    {
        if (!$event instanceof ApplicationStartup) {
            return null;
        }

        return $this->isCommandActive($event->commandName);
    }
}

final class EverythingActivator implements ActivatorInterface
{
    public function isActive($event): ?bool
    {
        return true;
    }
}

Configuration for Debugger could be then:

'activators' => [
    new IgnoreRequestActivator(urls: ['a', 'b']),
    new IgnoreCommandActivator(commands: ['a', 'b']),
    new EverythingActivator(),
],

samdark avatar Sep 26 '24 09:09 samdark

Or we can make it as psr middlewares look like: passing next handler into the activator method, I like more the second option, but it's open for discussion.

Basically, activator may be connected to any point in the application: catch request and check user ip, listen for "authenticated" event and check role, listen for an exception, parse command line arguments.

In general looks good, I'd also use enums as a ?bool replacement.

Also I think it cannot be just a class that only returns true/false, but be a service that call debugger? Just thinking.

xepozz avatar Oct 14 '24 16:10 xepozz

Also it may be useful to use this concept for each collector separately.

vjik avatar Oct 19 '24 16:10 vjik