Skip to content

Commit

Permalink
Merge branch 'master' into v4
Browse files Browse the repository at this point in the history
  • Loading branch information
itsgoingd committed Apr 6, 2020
2 parents 30d54ec + 81556bb commit 74f1b4d
Show file tree
Hide file tree
Showing 65 changed files with 1,516 additions and 448 deletions.
37 changes: 36 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
4.1

- added support for command type requests with command specific metadata (commandName, commandArguments, commandArgumentsDefaults, commandOptions, commandOptionsDefaults, commandExitCode, commandOutput)
- added support for collecting executed artisan commands in Laravel integration
- added support for queue-job type requests with queue-job specific metadata (jobName, jobDescription, jobStatus, jobPayload, jobQueue, jobConnection, jobOptions)
- added support for collecting executed queue-jobs in Laravel integration (also supports Laravel Horizon)
- added support for test type requests with test specific metadata (testName, testStatus, testStatusMessage, testAsserts)
- added support for collecting test runs in Laravel integration using PHPunit
- added support for disabling collection of view data when collecting rendered views (new default is to collect views without data)
- added Twig data source using the built-in Twig profiler to collect more precise Twig profiling data
- added support for setting parent requests on requests
- improved collecting of database queries, cache queries, dispatched queue jobs and redis commands to also collect time
- improved the data sources filters api to allow multiple filter types
- improved collecting of Laravel views to use a separate data source
- improved Eloquent data source to have an additional "early" filter applied before the query is added to query counts
- improved Eloquent data source now passes raw stack trace as second argument to filters
- improved Laravel data source to work when response is not provided
- improved Laravel events data source to include Laravel namespace in the default ignored events
- improved Laravel views data source to strip view data prefixed with __
- improved PHP data source to not set request time for cli commands
- improved serializer to ommit data below depth limit, support debugInfo, jsonSerialize and toArray methods (partially implemented by mahagr, thanks!)
- improved log to allow overriding serializer settings via context, no longer enabled toString by default
- improved Request class now has pre-populated request time on creation
- improved StackTrace helper with limit option, last method, fixed filter output keys
- improved Lumen queue and redis feature detection
- improved vanilla integration to allow manually sending the headers early (implemented by tminich, thanks!)
- fixed Symfony support, added support for latest Symfony 5.x and 4.x (reported by llaville, thanks!)
- removed dark theme for the web UI setting (now configurable in the Clockwork app itself)
- updated to Clockwork App 4.1

*BREAKING*

- multiple new settings were added to the Laravel config file
- DataSourceInterface::reset method was added, default empty implementation is provided in the base DataSource class
- LaravelDataSource constructor arguments changed to reflect removing the views collecting support

4.0.17

- improved performance and memory usage when doing file storage cleanup (reported by ikkez, thanks!)
Expand All @@ -22,7 +58,6 @@
- fixed wrong stack traces skip namespaces defaults leading to wrong traces
- fixed vanilla integration config file missing and no longer used settings


4.0.12

- added a simple index file locking to the file storage
Expand Down
69 changes: 68 additions & 1 deletion Clockwork/Clockwork.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
use Clockwork\Authentication\AuthenticatorInterface;
use Clockwork\Authentication\NullAuthenticator;
use Clockwork\DataSource\DataSourceInterface;
use Clockwork\Helpers\Serializer;
use Clockwork\Request\Log;
use Clockwork\Request\Request;
use Clockwork\Request\RequestType;
use Clockwork\Request\Timeline;
use Clockwork\Storage\StorageInterface;

Expand All @@ -19,7 +21,7 @@ class Clockwork implements LoggerInterface
/**
* Clockwork version
*/
const VERSION = '4.0.17';
const VERSION = '4.1';

/**
* Array of data sources, these objects provide data to be stored in a request object
Expand Down Expand Up @@ -122,6 +124,58 @@ public function resolveRequest()
return $this;
}

// Resolve the current request as a "command" type request with command-specific data
public function resolveAsCommand($name, $exitCode = null, $arguments = [], $options = [], $argumentsDefaults = [], $optionsDefaults = [], $output = null)
{
$this->resolveRequest();

$this->request->type = RequestType::COMMAND;
$this->request->commandName = $name;
$this->request->commandArguments = $arguments;
$this->request->commandArgumentsDefaults = $argumentsDefaults;
$this->request->commandOptions = $options;
$this->request->commandOptionsDefaults = $optionsDefaults;
$this->request->commandExitCode = $exitCode;
$this->request->commandOutput = $output;

return $this;
}

// Resolve the current request as a "queue-job" type request with queue-job-specific data
public function resolveAsQueueJob($name, $description = null, $status = 'processed', $payload = [], $queue = null, $connection = null, $options = [])
{
$this->resolveRequest();

$this->request->type = RequestType::QUEUE_JOB;
$this->request->jobName = $name;
$this->request->jobDescription = $description;
$this->request->jobStatus = $status;
$this->request->jobPayload = (new Serializer)->normalize($payload);
$this->request->jobQueue = $queue;
$this->request->jobConnection = $connection;
$this->request->jobOptions = (new Serializer)->normalizeEach($options);

return $this;
}

// Resolve the current request as a "test" type request with test-specific data, accepts test name, status, status
// message in case of failure and array of ran asserts
public function resolveAsTest($name, $status = 'passed', $statusMessage = null, $asserts = [])
{
$this->resolveRequest();

$this->request->type = RequestType::TEST;
$this->request->testName = $name;
$this->request->testStatus = $status;
$this->request->testStatusMessage = $statusMessage;

foreach ($asserts as $assert) {
$this->request->addTestAssert($assert['name'], $assert['arguments'], $assert['passed'], $assert['trace']);
}

return $this;
}

// Extends the request with additional data form all data sources when being shown in the Clockwork app
public function extendRequest(Request $request = null)
{
Expand All @@ -140,6 +194,19 @@ public function storeRequest()
return $this->storage->store($this->request);
}

// Reset the log, timeline and all data sources to an empty state, clearing any collected data
public function reset()
{
foreach ($this->dataSources as $dataSource) {
$dataSource->reset();
}

$this->log = new Log;
$this->timeline = new Timeline;

return $this;
}

/**
* Return the storage object
*/
Expand Down
16 changes: 13 additions & 3 deletions Clockwork/DataSource/DBALDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public function stopQuery()
{
$duration = (microtime(true) - $this->start) * 1000;

$this->registerQuery($this->query['sql'], $this->query['params'], $duration, $this->connection->getDatabase());
$this->registerQuery($this->query['sql'], $this->query['params'], $duration, $this->connection->getDatabase(), $this->start);

if ($this->timeline !== null) {
$this->timeline->endEvent(self::EVENT_NAME);
Expand All @@ -190,13 +190,14 @@ public function stopQuery()
/**
* Log the query into the internal store
*/
public function registerQuery($query, $bindings, $duration, $connection)
public function registerQuery($query, $bindings, $duration, $connection, $time)
{
$query = [
'query' => $query,
'bindings' => $bindings,
'duration' => $duration,
'connection' => $connection
'connection' => $connection,
'time' => $time
];

if ($this->passesFilters([ $query ])) {
Expand All @@ -214,6 +215,15 @@ public function resolve(Request $request)
return $request;
}

// Reset the data source to an empty state, clearing any collected data
public function reset()
{
$this->queries = [];

$this->start = null;
$this->query = null;
}

/**
* Timeline Getter/Setter
*/
Expand Down
16 changes: 12 additions & 4 deletions Clockwork/DataSource/DataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ public function extend(Request $request)
return $request;
}

// Reset the data source to an empty state, clearing any collected data
public function reset()
{
}

// Register a new filter
public function addFilter(\Closure $filter)
public function addFilter(\Closure $filter, $type = 'default')
{
$this->filters[] = $filter;
$this->filters[$type] = isset($this->filters[$type])
? array_merge($this->filters[$type], [ $filter ]) : [ $filter ];

return $this;
}
Expand All @@ -41,9 +47,11 @@ public function clearFilters()
}

// Returns boolean whether the filterable passes all registered filters
protected function passesFilters($args)
protected function passesFilters($args, $type = 'default')
{
foreach ($this->filters as $filter) {
$filters = isset($this->filters[$type]) ? $this->filters[$type] : [];

foreach ($filters as $filter) {
if (! call_user_func_array($filter, $args)) return false;
}

Expand Down
3 changes: 3 additions & 0 deletions Clockwork/DataSource/DataSourceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ public function resolve(Request $request);

// Extends the request with additional data when being shown in the Clockwork app
public function extend(Request $request);

// Reset the data source to an empty state, clearing any collected data
public function reset();
}
34 changes: 20 additions & 14 deletions Clockwork/DataSource/EloquentDataSource.php
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,9 @@ class EloquentDataSource extends DataSource

// Query counts by type
protected $count = [
'total' => 0,
'slow' => 0,
'select' => 0,
'insert' => 0,
'update' => 0,
'delete' => 0,
'other' => 0
'total' => 0, 'slow' => 0, 'select' => 0, 'insert' => 0, 'update' => 0, 'delete' => 0, 'other' => 0
];

// Array of filter functions for collected queries
protected $filters = [];

// Whether we are collecting cache queries or stats only
protected $collectQueries = true;

Expand Down Expand Up @@ -105,20 +96,23 @@ public function registerQuery($event)
'query' => $this->createRunnableQuery($event->sql, $event->bindings, $event->connectionName),
'duration' => $event->time,
'connection' => $event->connectionName,
'time' => microtime(true) - $event->time / 1000,
'trace' => $shortTrace = (new Serializer)->trace($trace),
'file' => isset($shortTrace[0]) ? $shortTrace[0]['file'] : null,
'line' => isset($shortTrace[0]) ? $shortTrace[0]['line'] : null,
'model' => $this->nextQueryModel,
'tags' => $this->slowThreshold !== null && $event->time > $this->slowThreshold ? [ 'slow' ] : []
];

$this->nextQueryModel = null;

if (! $this->passesFilters([ $query, $trace ], 'early')) return;

$this->incrementQueryCount($query);

if ($this->collectQueries && $this->passesFilters([ $query ])) {
$this->queries[] = $query;
}
if (! $this->collectQueries || ! $this->passesFilters([ $query, $trace ])) return;

$this->nextQueryModel = null;
$this->queries[] = $query;
}

/**
Expand Down Expand Up @@ -154,6 +148,18 @@ public function resolve(Request $request)
return $request;
}

// Reset the data source to an empty state, clearing any collected data
public function reset()
{
$this->queries = [];

$this->count = [
'total' => 0, 'slow' => 0, 'select' => 0, 'insert' => 0, 'update' => 0, 'delete' => 0, 'other' => 0
];

$this->nextQueryModel = null;
}

/**
* Takes a query, an array of bindings and the connection as arguments, returns runnable query with upper-cased keywords
*/
Expand Down
17 changes: 12 additions & 5 deletions Clockwork/DataSource/LaravelCacheDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ class LaravelCacheDataSource extends DataSource

// Query counts by type
protected $count = [
'read' => 0,
'hit' => 0,
'write' => 0,
'delete' => 0
'read' => 0, 'hit' => 0, 'write' => 0, 'delete' => 0
];

// Whether we are collecting cache queries or stats only
Expand Down Expand Up @@ -97,6 +94,16 @@ public function resolve(Request $request)
return $request;
}

// Reset the data source to an empty state, clearing any collected data
public function reset()
{
$this->queries = [];

$this->count = [
'read' => 0, 'hit' => 0, 'write' => 0, 'delete' => 0
];
}

/**
* Registers a new query, resolves caller file and line no
*/
Expand All @@ -108,7 +115,7 @@ public function registerQuery(array $query)
'type' => $query['type'],
'key' => $query['key'],
'value' => isset($query['value']) ? (new Serializer)->normalize($query['value']) : null,
'time' => null,
'time' => microtime(true),
'connection' => null,
'trace' => $shortTrace = (new Serializer)->trace($trace),
'file' => isset($shortTrace[0]) ? $shortTrace[0]['file'] : null,
Expand Down
Loading

0 comments on commit 74f1b4d

Please sign in to comment.