-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 64664ef
Showing
14 changed files
with
1,131 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# This is a basic workflow to help you get started with Actions | ||
|
||
name: testing | ||
|
||
# Controls when the action will run. | ||
on: | ||
# Triggers the workflow on push or pull request events but only for the master branch | ||
push: | ||
branches: [ master ] | ||
pull_request: | ||
branches: [ master ] | ||
|
||
workflow_dispatch: | ||
|
||
jobs: | ||
test: | ||
runs-on: ${{ matrix.os }} | ||
|
||
services: | ||
mysql: | ||
image: mysql:5.7 | ||
env: | ||
MYSQL_ALLOW_EMPTY_PASSWORD: yes | ||
MYSQL_USER: root | ||
MYSQL_DATABASE: test_db | ||
ports: | ||
- 3306:3306 | ||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 | ||
|
||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: [ ubuntu-latest] | ||
php: [ 7.4 ] | ||
laravel: [ 6.*, 7.*, 8.* ] | ||
include: | ||
- laravel: 6.* | ||
testbench: 4.* | ||
- laravel: 7.* | ||
testbench: 5.* | ||
- laravel: 8.* | ||
testbench: 6.* | ||
|
||
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Cache dependencies | ||
uses: actions/cache@v2 | ||
with: | ||
path: ~/.composer/cache/files | ||
key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} | ||
|
||
- name: Setup PHP | ||
uses: shivammathur/setup-php@v2 | ||
with: | ||
php-version: ${{ matrix.php }} | ||
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick | ||
coverage: none | ||
|
||
- name: Install dependencies | ||
run: | | ||
composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update | ||
composer update --prefer-dist --no-interaction --no-suggest | ||
- name: Execute tests | ||
env: | ||
DB_CONNECTION: mysql | ||
DB_DATABASE: test_db | ||
DB_PORT: ${{ job.services.mysql.ports[3306] }} | ||
DB_USER: root | ||
DB_HOST: 127.0.0.1 | ||
run: vendor/bin/phpunit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/vendor | ||
composer.phar | ||
composer.lock | ||
.phpunit.result.cache | ||
.php_cs.cache | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
{ | ||
"name": "muhdfaiz/laravel-tail-db", | ||
"description": "Provide artisan command to tail database query. Able to automatically run explain command for each of query received.", | ||
"keywords": [ | ||
"laravel", | ||
"tail", | ||
"log", | ||
"explain", | ||
"query", | ||
"database", | ||
"tail-db" | ||
], | ||
"type": "library", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "Muhammad Faiz", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"require": { | ||
"php": "^7.0", | ||
"symfony/process": "^4.0|^5.0" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "^8.0|^9.0", | ||
"laravel/framework": "^6.0|^7.0|^8.0", | ||
"orchestra/testbench": "^4.0|^5.0|^6.0" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"Muhdfaiz\\LaravelTailDb\\": "src/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"Muhdfaiz\\LaravelTailDb\\Tests\\": "tests" | ||
} | ||
}, | ||
"extra": { | ||
"laravel": { | ||
"providers": [ | ||
"Muhdfaiz\\LaravelTailDb\\TailDatabaseServiceProvider" | ||
] | ||
} | ||
}, | ||
"prefer-stable": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<?php | ||
|
||
return [ | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Laravel Tail Database Switch | ||
|-------------------------------------------------------------------------- | ||
| | ||
| This option used to enable or disable the Laravel Tail DB watcher. | ||
| If enabled, every sql query executed from the application will | ||
| be captured and store in the directory you based on the config. | ||
| | ||
*/ | ||
'enabled' => env('TAIL_DB_ENABLED', true), | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Duration of time considered slow query. | ||
|-------------------------------------------------------------------------- | ||
| | ||
| This option used to tell Laravel Tail DB if the query slow or not. | ||
| For example, if you specify 2000ms and the last query executed take | ||
| more than 2000ms, Laravel Tail DB will highlight the time with red color. | ||
| If the query below than 2000ms Laravel Tail DB will highlight with green color. | ||
| The value must be in milliseconds. | ||
*/ | ||
'slow_duration' => env('TAIL_DB_SLOW_DURATION', 3000), | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Ignore queries | ||
|-------------------------------------------------------------------------- | ||
| | ||
| You can specify the keyword to skip the tailing. | ||
| Laravel Tail DB will check if the query contain those keyword or not. | ||
| If exist, Laravel Tail DB will skip recording to log file. | ||
| The key keyword must be separated by comma. | ||
| Example: alter table}drop table. (Separated by |) | ||
| | ||
*/ | ||
'ignore_query_keyword' => env('TAIL_DB_IGNORE_QUERY_KEYWORD', ''), | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Filename to store mysql queries log | ||
|-------------------------------------------------------------------------- | ||
| | ||
| Default filename is database.log | ||
| | ||
*/ | ||
'filename' => env ('TAIL_DB_FILENAME', 'database.log'), | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Path to store sql queries log. | ||
|-------------------------------------------------------------------------- | ||
| | ||
| Default path is inside storage/logs. | ||
| | ||
*/ | ||
'path' => env ('TAIL_DB_PATH', storage_path('logs')), | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Show explain sql during the tail. | ||
|-------------------------------------------------------------------------- | ||
| | ||
| By default every sql query executed, laravel tail db will run explain | ||
| command. Useful if you want to troubleshooting performance issue. | ||
| If turn off, Laravel Tail DB only show the query executed, the time and | ||
| the location where the query executed. | ||
*/ | ||
'show_explain' => env ('TAIL_DB_SHOW_EXPLAIN', true), | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Clear log | ||
|-------------------------------------------------------------------------- | ||
| | ||
| When you end the tail:database command or every time Laravel Tail DB | ||
| received new data, the data in the log will be cleared. | ||
*/ | ||
'clear_log' => env ('TAIL_DB_CLEAR_LOG', true), | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit bootstrap="vendor/autoload.php" | ||
backupGlobals="false" | ||
backupStaticAttributes="false" | ||
colors="true" | ||
verbose="true" | ||
convertErrorsToExceptions="true" | ||
convertNoticesToExceptions="true" | ||
convertWarningsToExceptions="true" | ||
processIsolation="false" | ||
stopOnFailure="false"> | ||
<testsuites> | ||
<testsuite name="Laravel Tail Database Test Suite"> | ||
<directory>tests</directory> | ||
</testsuite> | ||
</testsuites> | ||
<filter> | ||
<whitelist> | ||
<directory suffix=".php">src/</directory> | ||
</whitelist> | ||
</filter> | ||
<php> | ||
<env name="APP_KEY" value="base64:m+pDa0MKS1KpMlxzzdVEaqFHysv3IPhrx/3TFSWBqJA=" /> | ||
</php> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
<?php | ||
|
||
namespace Muhdfaiz\LaravelTailDb; | ||
|
||
use Illuminate\Contracts\Foundation\Application; | ||
use Illuminate\Database\Events\QueryExecuted; | ||
use Illuminate\Support\Facades\Log; | ||
use Illuminate\Support\Str; | ||
|
||
class DatabaseWatcher | ||
{ | ||
/** | ||
* Register the watcher. | ||
* | ||
* @param Application $app | ||
* @return void | ||
*/ | ||
public function register($app) | ||
{ | ||
$app['events']->listen(QueryExecuted::class, [$this, 'recordQuery']); | ||
} | ||
|
||
/** | ||
* Record a query was executed. | ||
* | ||
* @param QueryExecuted $event | ||
* @return void | ||
*/ | ||
public function recordQuery(QueryExecuted $event) | ||
{ | ||
// Check if the query contain keywords user want to ignore based on the config. | ||
if (config('tail-db.ignore_query_keyword') && preg_match('(' . config('tail-db.ignore_query_keyword') . ')', strtolower($event->sql)) === 1) { | ||
return; | ||
} | ||
|
||
// Need to skip recording if the query received related to migration. | ||
// For example, create table, drop table and alter table. | ||
if ($this->checkIfQueryRelatedToMigration(strtolower($event->sql))) { | ||
return; | ||
}; | ||
|
||
// Get stack trace. | ||
$caller = $this->getCallerFromStackTrace(); | ||
|
||
// Set data before storing in the database log file. | ||
$data = [ | ||
'connection' => $event->connectionName, | ||
'bindings' => $event->bindings, | ||
'sql' => strtolower($this->replaceBindings($event)), | ||
'time' => number_format($event->time, 2, '.', ''), | ||
'file' => $caller['file'], | ||
'line' => $caller['line'], | ||
]; | ||
|
||
// Store the data in the log file. | ||
Log::channel('taildb')->info(json_encode($data)); | ||
} | ||
|
||
/** | ||
* Find the first frame in the stack trace outside of Laravel vendor. | ||
* | ||
* @return array | ||
*/ | ||
protected function getCallerFromStackTrace() | ||
{ | ||
$trace = collect(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS))->forget(0); | ||
return $trace->first(function ($frame) { | ||
if (! isset($frame['file'])) { | ||
return false; | ||
} | ||
|
||
if (Str::contains($frame['file'],'vendor'.DIRECTORY_SEPARATOR.'laravel')) { | ||
return false; | ||
} | ||
|
||
return $frame['file']; | ||
}); | ||
} | ||
|
||
/** | ||
* Format the given bindings to strings. | ||
* | ||
* @param QueryExecuted $event | ||
* | ||
* @return array | ||
*/ | ||
protected function formatBindings($event) | ||
{ | ||
return $event->connection->prepareBindings($event->bindings); | ||
} | ||
|
||
/** | ||
* Replace the placeholders with the actual bindings. | ||
* | ||
* @param QueryExecuted $event | ||
* | ||
* @return string | ||
*/ | ||
public function replaceBindings($event) | ||
{ | ||
$sql = $event->sql; | ||
|
||
foreach ($this->formatBindings($event) as $key => $binding) { | ||
$regex = is_numeric($key) | ||
? "/\?(?=(?:[^'\\\']*'[^'\\\']*')*[^'\\\']*$)/" | ||
: "/:{$key}(?=(?:[^'\\\']*'[^'\\\']*')*[^'\\\']*$)/"; | ||
|
||
if ($binding === null) { | ||
$binding = 'null'; | ||
} elseif (! is_int($binding) && ! is_float($binding)) { | ||
$binding = $event->connection->getPdo()->quote($binding); | ||
} | ||
|
||
$sql = preg_replace($regex, $binding, $sql, 1); | ||
} | ||
|
||
return $sql; | ||
} | ||
|
||
/** | ||
* Check if query related to migration. | ||
* | ||
* @param $query | ||
* | ||
* @return bool | ||
*/ | ||
private function checkIfQueryRelatedToMigration($query) | ||
{ | ||
$query = strtolower($query); | ||
|
||
// Get ignore query from the config in case user want to ignore other query. | ||
|
||
|
||
// Default query that will skip by Laravel Tail DB. | ||
if (strpos($query, 'explain') !== false || strpos($query, 'alter table') !== false | ||
|| strpos($query, 'create table') !== false || strpos($query, 'drop table') !== false | ||
|| strpos($query, 'create index') !== false || strpos($query, 'create unique index') !== false | ||
|| strpos($query, 'information_schema') !== false | ||
) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
} |
Oops, something went wrong.