1. 程式人生 > 實用技巧 >swoft 事件監聽和觸發 列印sql日誌

swoft 事件監聽和觸發 列印sql日誌

需求 打印出swoft的所有sql日誌到控制檯或者檔案

只要開啟listener 下面 Dbranlisten.php 裡面最後一行註釋即可,swoft已經幫我們實現好了

    ____            _____    ___   ___
    / __/    _____  / _/ /_  |_  | / _ \
   _\ \| |/|/ / _ \/ _/ __/ / __/_/ // /
  /___/|__,__/\___/_/ \__/ /____(_)___/
  

                           SERVER INFORMATION(v2.0.9)
  ********************************************************************************
  * HTTP     | Listen: 0.0.0.0:18306, Mode: Process, Worker: 6, Task worker: 12
  ********************************************************************************

HTTP Server Start Success!
2020/07/17-20:55:29 [INFO] Swoft\Server\Server:startSwoole(491) Swoole\Runtime::enableCoroutine
2020/07/17-20:55:29 [INFO] Swoft\Listener\BeforeStartListener:handle(27) Server extra info: pidFile @runtime/swoft.pid
2020/07/17-20:55:29 [INFO] Swoft\Listener\BeforeStartListener:handle(28) Registered swoole events:
 start, shutdown, managerStart, managerStop, workerStart, workerStop, workerError, request, task, finish
Server start success (Master PID: 17681, Manager PID: 17686)
[INFO] insert into `tb_users` (`name`, `age`, `created_at`) values ('test', 10, '2020-07-17 20:55:50')

為什麼會監聽到日誌 事件什麼時候觸發的

/**
* Class RanListener
*
* @since 2.0
*
* @Listener(DbEvent::SQL_RAN)
*/


/**
* Sql ran after
*/
public const SQL_RAN = 'swoft.db.ran';


全專案搜尋 DbEvent::SQL_RAN 發現除了呼叫的地方 還有寫入的地方
Connection.php 
/**
     * Run a SQL statement and log its execution context.
     *
     * @param string  $query
     * @param array   $bindings
     * @param Closure $callback
     *
     * @return mixed
     *
     * @throws DbException
     */
    protected function run(string $query, array $bindings, Closure $callback)
    {
        $this->reconnectIfMissingConnection();
        $start = microtime(true);
        // Here we will run this query. If an exception occurs we'll determine if it was
        // caused by a connection that has been lost. If that is the cause, we'll try
        $result = $this->runQueryCallback($query, $bindings, $callback);
        $time = $this->getElapsedTime($start);
        $this->fireEvent(DbEvent::SQL_RAN, $query, $bindings, $time);

        // Once we have run the query we will calculate the time that it took to run and
        // then log the query, bindings, and execution time so we will report them on
        // the event that the developer needs them. We'll log time in milliseconds.
        return $result;
    }


這個方法  $this->fireEvent(DbEvent::SQL_RAN, $query, $bindings, $time); 
往下 
HasEvent.php

   /**
     * Fire the given event for the model.
     *
     * @param string $event
     * @param mixed  ...$args
     *
     * @return bool
     */
    protected function fireEvent(string $event, ...$args): bool
    {
        // Trigger method public event
        $eventPublicResult = Swoft::trigger($event, $this, ...$args);
        if ($eventPublicResult->isPropagationStopped() === true) {
            return false;
        }

        // Not model no trigger
        if ($this->getContextName() !== 'model') {
            return true;
        }
        // Trigger model method event
        $modelEventResult = Swoft::trigger($this->getModelEventName($event), $this, ...$args);
        if ($modelEventResult->isPropagationStopped() === true) {
            return false;
        }

        return true;
    }

發現 Swoft::trigger($event, $this, ...$args); 

往下  Swoft.php
 /**
     * Trigger an swoft application event
     *
     * @param string|EventInterface $event eg: 'app.start' 'app.stop'
     * @param null|mixed            $target
     * @param array                 $params
     *
     * @return EventInterface
     */
    public static function trigger($event, $target = null, ...$params): EventInterface
    {

        /** @see EventManager::trigger() */
        return BeanFactory::getSingleton('eventManager')->trigger($event, $target, $params);
    }


EventManage.php 
  /**
     * Trigger an event. Can accept an EventInterface or will create one if not passed
     *
     * @param string|EventInterface $event  'app.start' 'app.stop'
     * @param mixed|string          $target It is object or string.
     * @param array|mixed           $args
     *
     * @return EventInterface
     * @throws InvalidArgumentException
     */
    public function trigger($event, $target = null, array $args = []): EventInterface
    {
        if ($isString = is_string($event)) {
            $name = trim($event);
        } elseif ($event instanceof EventInterface) {
            $name = trim($event->getName());
        } else {
            throw new InvalidArgumentException('Invalid event params for trigger event handler');
        }

        $shouldCall = [];

        // Have matched listener
        if (isset($this->listenedEvents[$name])) {
            $shouldCall[$name] = '';
        }

        // Like 'app.db.query' => prefix: 'app.db'
        if ($pos = strrpos($name, '.')) {
            $prefix = substr($name, 0, $pos);

            // Have a wildcards listener. eg 'app.db.*'
            $wildcardEvent = $prefix . '.*';
            if (isset($this->listenedEvents[$wildcardEvent])) {
                $shouldCall[$wildcardEvent] = substr($name, $pos + 1);
            }
        }

        // Not found listeners
        if (!$shouldCall) {
            return $isString ? $this->basicEvent : $event;
        }

        /** @var EventInterface $event */
        if ($isString) {
            $event = $this->events[$name] ?? $this->basicEvent;
        }

        // Initial value
        $event->setName($name);
        $event->setParams($args);
        $event->setTarget($target);
        $event->stopPropagation(false);

        // Notify event listeners
        foreach ($shouldCall as $name => $method) {
            $this->triggerListeners($this->listeners[$name], $event, $method);

            if ($event->isPropagationStopped()) {
                return $this->destroyAfterFire ? $event->destroy() : $event;
            }
        }

        // Have global wildcards '*' listener.
        if (isset($this->listenedEvents['*'])) {
            $this->triggerListeners($this->listeners['*'], $event);
        }

        return $this->destroyAfterFire ? $event->destroy() : $event;
    }

呼叫 triggerListeners 
/**
     * @param array|ListenerQueue $listeners
     * @param EventInterface      $event
     * @param string              $method
     */
    protected function triggerListeners($listeners, EventInterface $event, string $method = ''): void
    {
        // $handled = false;
        $name     = $event->getName();
        $callable = false === strpos($name, '.');

        // 迴圈呼叫監聽器,處理事件
        foreach ($listeners as $listener) {
            if ($event->isPropagationStopped()) {
                break;
            }

            if (is_object($listener)) {
                if ($listener instanceof EventHandlerInterface) {
                    $listener->handle($event);
                } elseif ($method && method_exists($listener, $method)) {
                    $listener->$method($event);
                } elseif ($callable && method_exists($listener, $name)) {
                    $listener->$name($event);
                } elseif (method_exists($listener, '__invoke')) {
                    $listener($event);
                }
            } elseif (is_callable($listener)) {
                $listener($event);
            }
        }
    }

最終呼叫監聽的 hadle方法  
 所以是 調動trigger 就會觸發匹配到的監聽,執行監聽的hanle方法  

  


模仿 自己觸發event 自己listen

控制器 HomeController 裡面新建方法
/**
	 * @RequestMapping("/add")
	 */
    public function add()
    {
//    	$user = new Users();
//    	$user->fill(['name'=>'test','age'=>10])->save();
//    	return $user;

	    Swoft::trigger("swoft.wang","this is message",'hello','world');
    }

  

app\Listener\Test\WangListener.php

<?php declare(strict_types=1);
/**
 * This file is part of Swoft.
 *
 * @link     https://swoft.org
 * @document https://swoft.org/docs
 * @contact  [email protected]
 * @license  https://github.com/swoft-cloud/swoft/blob/master/LICENSE
 */

namespace App\Listener\Test;

use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\Exception\SwoftException;
use Swoft\Log\Helper\CLog;
use Swoft\Server\SwooleEvent;

/**
 * Class ShutDownListener
 *
 * @since 2.0
 *
 * @Listener("swoft.wang")
 */
class WangListener implements EventHandlerInterface
{
    /**
     * @param EventInterface $event
     *
     * @throws SwoftException
     */
    public function handle(EventInterface $event): void
    {

        $message = $event->getTarget();
        $hello = $event->getParam(0);
        $world = $event->getParam(1);

        var_dump($message,$hello,$world);


        CLog::debug('this is a test trigger');
    }
}

訪問頁面 http://192.168.33.50:18306/add 發現結果為 如下 自己觸發的事件被自己監聽到了,打印出了引數

     ____            _____    ___   ___
    / __/    _____  / _/ /_  |_  | / _ \
   _\ \| |/|/ / _ \/ _/ __/ / __/_/ // /
  /___/|__,__/\___/_/ \__/ /____(_)___/
  

                           SERVER INFORMATION(v2.0.9)
  ********************************************************************************
  * HTTP     | Listen: 0.0.0.0:18306, Mode: Process, Worker: 6, Task worker: 12
  ********************************************************************************

HTTP Server Start Success!
2020/07/17-21:06:09 [INFO] Swoft\Server\Server:startSwoole(491) Swoole\Runtime::enableCoroutine
2020/07/17-21:06:09 [INFO] Swoft\Listener\BeforeStartListener:handle(27) Server extra info: pidFile @runtime/swoft.pid
2020/07/17-21:06:09 [INFO] Swoft\Listener\BeforeStartListener:handle(28) Registered swoole events:
 start, shutdown, managerStart, managerStop, workerStart, workerStop, workerError, request, task, finish
Server start success (Master PID: 17738, Manager PID: 17743)
string(15) "this is message"
string(5) "hello"
string(5) "world"