├── .github
├── FUNDING.yml
└── dependabot.yml
├── .gitignore
├── .travis.yml
├── README.md
├── composer.json
├── config
└── laravel-query-monitor.php
├── demo.gif
├── phpunit.xml
├── src
├── Commands
│ └── MonitorCommand.php
├── DispatchQueries.php
├── ListenQueries.php
└── ServiceProvider.php
└── tests
└── LaravelQueryMonitorTest.php
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | patreon: supliutech
4 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "composer" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.lock
3 | .DS_Store
4 | .phpunit.result.cache
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.3
5 | - 7.4
6 |
7 | before_script:
8 | - travis_retry composer self-update
9 | - travis_retry composer install --dev
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Laravel Query Monitor
2 | 
3 | 
4 |
5 | Supliu Laravel Query Monitor is library to monitoring Queries in real-time using Laravel Artisan Command. Basically it opens a socket listening and displays (on terminal) the queries executed in your Laravel application.
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## How to install
13 |
14 | 1) Use composer to install this package
15 |
16 | ```
17 | composer require --dev supliu/laravel-query-monitor
18 | ```
19 |
20 | 2) Run publish command
21 |
22 | ```ssh
23 | php artisan vendor:publish --provider="Supliu\LaravelQueryMonitor\ServiceProvider"
24 | ```
25 |
26 | ## How to use
27 |
28 | Open you terminal and execute:
29 |
30 | ```ssh
31 | php artisan laravel-query-monitor
32 | ```
33 |
34 | Now just perform some action in your application that performs some interaction with the database.
35 |
36 | ## Customize
37 |
38 | By default, the query listening service will run on host 0.0.0.0 and port 8081. You can customize both the host and the port by providing the optional arguments:
39 |
40 | ```ssh
41 | php artisan laravel-query-monitor --host="192.168.0.2" --port=8082
42 | ```
43 |
44 | If you change the host and port parameters, you will also need to change the configuration file `config/laravel-query-monitor.php`.
45 |
46 | ## License
47 |
48 | The Laravel Query Monitor is open-sourced project licensed under the [MIT license](https://opensource.org/licenses/MIT).
49 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "supliu/laravel-query-monitor",
3 | "type": "library",
4 | "description": "Laravel Query Monitor",
5 | "keywords": [
6 | "laravel", "eloquent", "query", "sql", "monitor"
7 | ],
8 | "authors": [
9 | {
10 | "name": "Jansen Felipe",
11 | "email": "jansen.felipe@gmail.com"
12 | }
13 | ],
14 | "license": "MIT",
15 | "autoload": {
16 | "psr-4": {
17 | "Supliu\\LaravelQueryMonitor\\": "src/"
18 | }
19 | },
20 | "require": {
21 | "laravel/framework": "^5.6 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0",
22 | "php": "^7.3 || ^7.4 || ^8.0 || ^8.1 || ^8.2 || ^8.3",
23 | "react/socket": "^1.4"
24 | },
25 | "extra": {
26 | "branch-alias": {
27 | "dev-master": "1.0-dev"
28 | },
29 | "laravel": {
30 | "providers": [
31 | "Supliu\\LaravelQueryMonitor\\ServiceProvider"
32 | ]
33 | }
34 | },
35 | "minimum-stability": "dev",
36 | "require-dev": {
37 | "phpunit/phpunit": "^9.2@dev",
38 | "orchestra/testbench": "^3.6 || ^4.0 || ^5.0 || ^6.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/config/laravel-query-monitor.php:
--------------------------------------------------------------------------------
1 | env('LARAVEL_QUERY_MONITOR', true),
5 | 'host' => env('LARAVEL_QUERY_MONITOR_HOST', '0.0.0.0'),
6 | 'port' => env('LARAVEL_QUERY_MONITOR_PORT', 8081),
7 |
8 | // The following options are used to filter the queries that are monitored.
9 | // Useful to ignore queries from Laravel Pulse, Telescope, etc.
10 | 'ignore_query_match' => [
11 | '/pulse_entries|pulse_aggregates|pulse_values/i',
12 | '/telescope_entries|telescope_entries_tags|telescope_monitoring/i',
13 | ],
14 | ];
15 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supliu/laravel-query-monitor/8acfd5aebe23e68295bda186bff20741e6822a04/demo.gif
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | tests
15 |
16 |
17 |
18 |
19 | src/
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/Commands/MonitorCommand.php:
--------------------------------------------------------------------------------
1 | option('host') ?? '0.0.0.0';
42 | $port = $this->option('port') ?? '8081';
43 | $debug = $this->option('debug') ?? false;
44 | $moreThanMiliseconds = $this->option('moreThanMiliseconds') ?? 0;
45 |
46 | $listenQueries = new ListenQueries($host, $port, $moreThanMiliseconds);
47 |
48 | $listenQueries->setInfo(function($message){
49 | $this->info($message);
50 | });
51 |
52 | $listenQueries->setWarn(function($message){
53 | $this->warn($message);
54 | });
55 |
56 | $listenQueries->setDebug($debug);
57 |
58 | $listenQueries->run();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/DispatchQueries.php:
--------------------------------------------------------------------------------
1 | host = $host;
34 | $this->port = $port;
35 | $this->loop = Factory::create();
36 | $this->connector = new Connector($this->loop);
37 | }
38 |
39 | public function send($query): void
40 | {
41 | $this->connector
42 | ->connect($this->host . ':' . $this->port)
43 | ->then(function (ConnectionInterface $connection) use ($query) {
44 | $connection->write(json_encode($query));
45 | });
46 |
47 | $this->loop->run();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/ListenQueries.php:
--------------------------------------------------------------------------------
1 | host = $host;
31 | $this->port = $port;
32 | $this->moreThanMiliseconds = $moreThanMiliseconds;
33 | $this->loop = Factory::create();
34 | $this->socket = new Server($host.':'.$port, $this->loop);
35 | }
36 |
37 | public function setInfo(Closure $info)
38 | {
39 | $this->info = $info;
40 | }
41 |
42 | public function setWarn(Closure $warn)
43 | {
44 | $this->warn = $warn;
45 | }
46 |
47 | public function setDebug(bool $debug)
48 | {
49 | $this->debug = $debug;
50 | }
51 |
52 | public function run()
53 | {
54 | call_user_func($this->info, 'Listen SQL queries on '.$this->host.':'.$this->port . PHP_EOL . PHP_EOL);
55 |
56 | $this->socket->on('connection', function (ConnectionInterface $connection) {
57 |
58 | $connection->on('data', function ($data) use ($connection) {
59 |
60 | if($this->debug)
61 | call_user_func($this->warn, '# Debug:' . $data);
62 |
63 | $query = json_decode($data, true);
64 |
65 |
66 | if ($query === null) {
67 | call_user_func($this->warn, '# Something wrong happened with JSON data received: ');
68 | call_user_func($this->info, $data);
69 | } else {
70 |
71 | if($query['time'] > $this->moreThanMiliseconds) {
72 |
73 | call_user_func($this->warn, '# Query received:');
74 |
75 | $bindings = $query['bindings'] ?? [];
76 |
77 | $normalizedBindings = array_map(function($i){
78 | return is_string($i) ? '"'.$i.'"' : $i;
79 | }, $bindings);
80 |
81 | $sql = Str::replaceArray('?', $normalizedBindings, $query['sql']);
82 |
83 | call_user_func($this->info, '# SQL: ' . $sql);
84 | call_user_func($this->info, '# Miliseconds: ' . $query['time']);
85 | call_user_func($this->info, '# Seconds: ' . $query['time'] / 1000);
86 | call_user_func($this->info, PHP_EOL);
87 | }
88 |
89 | }
90 |
91 |
92 | $connection->close();
93 |
94 | });
95 | });
96 |
97 | $this->loop->run();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/ServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->runningInConsole()) {
19 | $this->commands([
20 | MonitorCommand::class,
21 | ]);
22 | }
23 |
24 | $this->publishes([
25 | __DIR__.'/../config/laravel-query-monitor.php' => config_path('laravel-query-monitor.php'),
26 | ]);
27 |
28 | /*
29 | * Setting
30 | */
31 | $host = config('laravel-query-monitor.host');
32 | $port = config('laravel-query-monitor.port');
33 | $enable = config('laravel-query-monitor.enable');
34 | $ignore_query_match = config('laravel-query-monitor.ignore_query_match', []);
35 |
36 | if ($host && $port && $enable) {
37 | $dispatchQueries = new DispatchQueries($host, (int) $port);
38 |
39 | DB::listen(function ($query) use ($dispatchQueries, $ignore_query_match) {
40 | if (is_array($ignore_query_match) && !empty($ignore_query_match)) {
41 | foreach ($ignore_query_match as $ignore) {
42 | if (preg_match($ignore, $query->sql)) {
43 | return;
44 | }
45 | }
46 | }
47 | $dispatchQueries->send($query);
48 | });
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/LaravelQueryMonitorTest.php:
--------------------------------------------------------------------------------
1 | set('laravel-query-monitor.enable', true);
23 | $app['config']->set('laravel-query-monitor.host', '0.0.0.0');
24 | $app['config']->set('laravel-query-monitor.port', 8082);
25 | }
26 |
27 | /**
28 | * @test
29 | */
30 | public function runCommand()
31 | {
32 | // TODO
33 | }
34 | }
--------------------------------------------------------------------------------