Installation
Install the Clockwork library via Composer.
$ composer require itsgoingd/clockwork
Congratulations, you are done! To enable more features like commands or queue jobs profiling, publish the configuration file via the vendor:publish
Artisan command.
Note: If you are using the Laravel route cache, you will need to refresh it using the route:cache
Artisan command.
Old Laravel
For Laravel versions older than 5.5, you'll need to register the service provider, in your config/app.php
:
'providers' => [
...
Clockwork\Support\Laravel\ClockworkServiceProvider::class
]
If you'd like to use the Facade, add following to your config/app.php
:
'aliases' => [
...
'Clockwork' => Clockwork\Support\Laravel\Facade::class,
]
Lumen
Install the Clockwork library via Composer.
$ composer require itsgoingd/clockwork
Once Clockwork is installed, you need to register the Clockwork service provider, in your bootstrap/app.php
:
$app->register(Clockwork\Support\Lumen\ClockworkServiceProvider::class);
To enable more features like commands or queue jobs profiling use enviroment variables, see full list of available settings.
Note: For collecting database queries you'll need to enable $app->withEloquent()
in bootstrap/app.php
, this has no performance impact if your app executes database queries on most requests.
Symfony
Install the Clockwork library via Composer.
$ composer require itsgoingd/clockwork
Once Clockwork is installed, you need to register the Clockwork bundle in config/bundles.php
:
return [
...
Clockwork\Support\Symfony\ClockworkBundle::class => ['dev' => true]
]
Clockwork routes also need to be registered in config/routes.yaml
:
clockwork:
resource: '@ClockworkBundle/Resources/config/routing/clockwork.php'
Clockwork uses the Symfony profiler as the data provider, make sure it is enabled:
framework:
profiler: { collect: true }
Note: Symfony integration uses the built-in Symfony profiler. This means we can only show the same information as the Symfony Web Profiler, other Clockwork features are not available.
Other
Install the Clockwork library via Composer.
$ composer require itsgoingd/clockwork
Middleware
Clockwork includes PSR-15 compatible middleware for use with various compatible micro-frameworks like Slim, Mezzio or custom integrations.
For zero-configuration use, install the php-http/discovery
package and register the middleware:
use Clockwork\Support\Vanilla\ClockworkMiddleware;
$app->add(ClockworkMiddleware::init());
Alternatively, instead of using php-http/discovery
, you can manually set a response factory.
use Clockwork\Support\Vanilla\ClockworkMiddleware;
$app->add(ClockworkMiddleware::init()->withResponseFactory($app->getResponseFactory()));
You can also instantiate the middleware with a custom configured Clockwork instance, or disable routing if you want to set it up on your own.
use Clockwork\Support\Vanilla\Clockwork;
use Clockwork\Support\Vanilla\ClockworkMiddleware;
$clockwork = new Clockwork([ ... ]);
$app->add((new ClockworkMiddleware($clockwork))->withoutRouting());
$app->get('/__clockwork/{request:.+}', function ($request, $response) use ($clockwork) {
return $clockwork->usePsrMessage($request, $response)->handleMetadata();
});
Manual Setup
You can also manually setup Clockwork in a PSR-7 or pure vanilla application. Initialize Clockwork early in your application:
$clockwork = Clockwork\Support\Vanilla\Clockwork::init();
If you are using a dependency injection container it might be a good idea register the Clockwork instance.
Right before sending a response, we need to tell Clockwork to resolve and store metadata for current request.
$clockwork->requestProcessed();
We also need to setup a Clockwork REST API endpoint. This endpoint is used by the Clockwork clients to load metadata for your application requests.
By default Clockwork clients expect the data at /__clockwork
URI. If your application uses a router, you can simply setup a GET route for this URI and pass rest of the URL to Clockwork.
$router->get('/__clockwork/{request:.+}', function ($request) {
$clockwork = Clockwork\Support\Vanilla\Clockwork::init();
return new JsonResponse($clockwork->getMetadata($request));
}};
In a very simple app without router you can use a separate script. In this case we will also need to tell Clockwork where to load the data from using the api
option.
// clockwork.php
$clockwork = Clockwork\Support\Vanilla\Clockwork::init([ 'api' => '/clockwork.php?request=' ]);
$clockwork->handleMetadata();
In the first example we used the getMetadata
method which returns the metadata as an array, the returnMetadata
will also json-ecncode the data, send it to output and set appropriate headers.
PSR-7 applications
Clockwork support in a PSR-7 application can be implemented as a middleware.
return $clockwork->usePsrMessage($request, $response)->requestProcessed();
In this case Clockwork will use the data from the PSR-7 request and return the PSR-7 response extended with Clockwork headers.
Configuration
The vanilla Clockwork integration can be configured by passing a configuration array to the init
method.
$clockwork = Clockwork\Support\Vanilla\Clockwork::init([
'storage_files_path' => __DIR__ . '/storage/clockwork'
]);
You can find the full list of options with descriptions in the configuration file.
You can also configure most options via environment variables, in this case you don't have to pass them to the init
method.
The clock helper
Clockwork includes a clock
global helper function providing easy access to Clockwork features from anywhere in the app.
The clock
helper is disabled by default in the vanilla integration, to enable the helper, use the register_helpers
option.
$clockwork = Clockwork\Support\Vanilla\Clockwork::init([ 'register_helpers' => true ]);
clock('Log', 'something');
clock()->addDatabaseQuery('SELECT * FROM users WHERE id = 1', [], 10);
Registering database queries
There are many ways to make database queries in a vanilla PHP application. That's why unlike a framework integration, it's up to you to register the executed database queries.
To do so, you can use the Clockwork addDatabaseQuery
method in your database abstraction layer. If you don't have one, you can write a simple helper function or class for making queries, eg. this helper function for executing queries using PDO and logging them to Clockwork.
function database_query($pdo, $query, $bindings) {
$time = microtime(true);
$stmt = $pdo->prepare($query);
$stmt->execute($bindings);
$results = $stmt->fetchAll();
clock()->addDatabaseQuery($query, $bindings, (microtime(true) - $time) * 1000);
return $results;
}
You can use a similar approach to logging cache queries, events, sent emails, etc. see the source of the main Clockwork class for a list of all available methods.
Web interface
The Clockwork library contains an optional web interface for interacting with the collected data that can be used instead of the browser extension.
To serve the web app the vanilla integration contains a Clockwork::returnWeb
api, which copies the web app assets to a publicly accessible path on the first use. You will also need to enable the web UI in the configuration, set the publicly accessible path where the assets will be copied and the uri where this path is accessible.
Note, the assets are not automatically updated, you should manually remove the assets when updating Clockwork so a new version could be installed.
If your application uses a router, you can set up a GET route calling this api, in this example we use a PSR-7 compatible router.
$router->get('/clockwork', function ($request) {
$clockwork = Clockwork\Support\Vanilla\Clockwork::init([
'web' => [
'enable' => true,
'path' => __DIR__ . '/public/vendor/clockwork',
'uri' => '/vendor/clockwork'
]
]);
return $clockwork->usePsrMessage($request, new Response)->returnWeb();
}};
In a very simple app without router you can use a separate script.
// clockwork-web.php
$clockwork = Clockwork\Support\Vanilla\Clockwork::init([
'api' => '/clockwork.php?request=',
'web' => [
'enable' => true,
'path' => __DIR__ . '/vendor/clockwork',
'uri' => '/vendor/clockwork'
]
]);
$clockwork->returnWeb();
Upgrade guide
5.0
Estimated upgrade time: 0 to 10 minutes
Config file
The Clockwork config file contains multiple changes. Please review and re-publish the config file.
Required PHP version
The minimum required PHP version is now 5.6, previously 5.5. If you can't upgrade, you can use Clockwork 4 indefinetly.
Timeline api
The timeline api was completely reworked, please see the "timeline" section in documentation for details.
In general, the old calls can be easily converted to the new api, eg.:
clock()->startEvent('twitter-api-call', "Loading user's latest tweets via Twitter API");
...
clock()->endEvent('twitter-api-call');
clock()->event("Loading user's latest tweets via Twitter API")->start();
...
clock()->event("Loading user's latest tweets via Twitter API")->end();
Global log and timeline instances
The global log and timeline instances were moved to the request instance.
// old api
$log = clock()->getLog();
// new api
$log = clock()->getRequest()->log();
Request's log and timelineData attributes should never be manually modified in custom data sources, the log or timeline instances should be used instead, eg.:
// old api
$request->log = array_merge($request->log, $localLog->toArray());
// new api
$request->log()->merge($localLog);
The clockwork.log
and Clockwork\Request\Log::class
are no longer registered in Laravel container.
The clockwork.controller.start
and clockwork.controller.end
events are no longer used and can be removed.
Central Clockwork class api
Central Clockwork class getters and setters are replaced with a single unified methods, eg. getRequest() -> request()
, setRequest($request) -> request($request)
.
Old getters and setters are still available but deprecated.
Removed deprecated Clockwork::subrequest()
method, use Clockwork::addSubrequest()
.
Slim 4 support
Slim 4 support has been added, original middleware namespaces were changed.
use Clockwork\Support\Slim\ClockworkMiddleware; // for Slim 4
use Clockwork\Support\Slim\Legacy\ClockworkMiddleware; // for Slim 3
use Clockwork\Support\Slim\Old\ClockworkMiddleware; // for Slim 2
See also the Slim installation section in the documentation.
Features
Collecting data
The Clockwork server-side component collects and stores data about your application.
Clockwork is only active when your app is in debug mode and running on a local domain - localhost, .local, .test, .wip and 127.0.0.1 - by default. You can choose to explicitly enable or disable Clockwork, or even set Clockwork to always collect data without exposing them for further analysis.
We collect a whole bunch of useful data by default, but you can enable more features or disable features you don't need in the config file.
Some features might allow for advanced options, eg. for database queries you can set a slow query threshold or enable detecting of duplicate (N+1) queries. Check out the config file to see all what Clockwork can do.
There are several options that allow you to choose for which requests Clockwork is active.
On-demand mode will collect data only when Clockwork app is open. You can even specify a secret to be set in the app settings to collect request. Errors only will record only requests ending with 4xx and 5xx responses. Slow only will collect only requests with responses above the set slow threshold. You can also filter the collected and recorded requests by a custom closure. CORS pre-flight requests will not be collected by default.
New in Clockwork 4.1, artisan commands, queue jobs and tests can now also be collected, you need to enable this in the config file.
Clockwork also collects stack traces for data like log messages or database queries. Last 10 frames of the trace are collected by default. You can change the frames limit or disable this feature in the configuration file.
Artisan commands
Clockwork supports collecting data about executed Artisan commands with optional support for collecting the command output. This is disabled by default and needs to be enabled in the config file.
Queue jobs
Clockwork supports collecting data about executed queue jobs with support for both the default Laravel queue worker and Laravel Horizon. This is disabled by default and needs to be enabled in the config file.
Tests
Clockwork supports collecting data about ran tests with support for the default Laravel PHPUnit or Pest testing setup. This is disabled by default and needs to be enabled in the config file.
PHPUnit 10 or Pest
To collect data about executed tests, you also need to register a Clockwork PHPUnit extension. Add following to your phpunit.xml
:
<extensions>
<bootstrap class="Clockwork\Support\Laravel\Tests\ClockworkExtension" />
</extensions>
PHPUnit 9 or older
To collect data about executed tests, you also need to add and boot a Clockwork testing trait in your tests/TestCase.php
:
use Clockwork\Support\Laravel\Tests\UsesClockwork;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication, RefreshDatabase, UsesClockwork;
protected function setUp() :void
{
parent::setUp();
$this->setUpClockwork();
}
}
Viewing data
Web interface
Open your.app/clockwork
to view and interact with the collected data.
The app will show all executed requests, which is useful when the request is not made by browser, but for example a mobile application you are developing an API for.
Browser extension
A browser dev tools extension is also available for Chrome and Firefox:
Toolbar
Clockwork now gives you an option to show basic request information in the form of a toolbar in your app.
The toolbar is fully rendered client-side and requires installing a tiny javascript library.
Use the following script tag to load the library from cdn:
<script src="https://cdn.jsdelivr.net/gh/underground-works/clockwork-browser@1/dist/toolbar.js"></script>
The cdn builds are transpiled to support all browsers with more than 1% market share. The cdn bundle sizes are 7.11K for metrics.js and 24.2K for toolbar.js.
Alternatively, you can install the library via npm:
npm install clockwork-browser
And import into your javascript bundle, no further configuration needed:
import 'clockwork-browser/toolbar'
The toolbar implementation uses cookies, if your website can't use cookies you might want to disable this feature.
Logging
You can log any variable via the clock()
helper, from a simple string to an array or object, even multiple values:
clock(User::first(), auth()->user(), $username)
The clock()
helper function returns it's first argument, so you can easily add inline debugging statements to your code:
User::create(clock($request->all()))
If you want to specify a log level, you can use the long-form call:
clock()->info("User {$username} logged in!")
You can add a context to the log message via the second argument, serializer options can be passed in the context array:
clock()->info("Trace this message!", [ 'trace' => true ])
You can use the performance
option to make the log message appear in the performance tab.
clock()->info("Api request {$method} {$uri}, took too long! ({$time})", [ 'performance' => true ])
All data logged using the standard Laravel log methods will also be collected.
Timeline
Timeline gives you a visual representation of your application runtime.
To add an event to the timeline - start it with a description, execute the tracked code and finish the event. A fluent api is available to further configure the event.
// using timeline api with begin/end and fluent configuration
clock()->event('Importing tweets')->color('purple')->begin();
...
clock()->event('Importing tweets')->end();
Alternatively you can execute the tracked code block as a closure. You can also choose to use an array based configuration instead of the fluent api.
// using timeline api with run and array-based configuration
clock()->event('Updating cache', [ 'color' => 'green' ])->run(function () {
...
});
Events have an optional unique name in case the description is not unique.
foreach ($users as $i => $user) {
clock()->event('Importing tweets')->name("importing-tweets-{$i}")->begin();
...
clock()->event("importing-tweets-{$i}")->end();
}
All possible event properties are - description, name, start, end, duration, color and data.
// manually adding event with start and end time
clock()->event('Importing tweets')
->start($startTime)
->end($endTime)
->color('purple');
// manually adding event with start time and duration (in ms)
clock()->event('Updating cache')
->start($startTime)
->duration($durationMs)
->color('green');
Client-metrics
Clockwork helps you to keep your server-side performance in check. Optimizing the backend is just half of the battle though. Javascript processing can still make your application feel sluggish. Fortunately we have some great web performance intiatives like Web Vitals and browser apis to help us measure how are we doing on this front.
With Clockwork 5 you are now be able to collect these client-side performance metrics. Supported are both navigation timings (like how long it took for the DOM interactive or complete event) and Web Vitals. You will find the collected metrics in a new client-side section in the performance tab.
Collecting client-side metrics requires installing a tiny javascript library.
Use the following script tag to load the library from cdn:
<script src="https://cdn.jsdelivr.net/gh/underground-works/clockwork-browser@1/dist/metrics.js"></script>
The cdn builds are transpiled to support all browsers with more than 1% market share. The cdn bundle sizes are 7.11K for metrics.js and 24.2K for toolbar.js.
Alternatively, you can install the library via npm:
npm install clockwork-browser
And import into your javascript bundle, no further configuration needed:
import 'clockwork-browser/metrics'
The metrics implementation uses cookies, if your website can't use cookies you might want to disable this feature.
Sharing
Sharing a request uploads the metadata to a Clockwork share service and gives you a public link to share with others. On this link you will find a fully working Clockwork app showing the request you shared. Append .png to the url and you will get a screenshot of the performance tab you can easily embed to a GitHub issue. You can also choose to share only part of the request, like the database tab.
The share service is free to use. The shared data is hosted on DigitalOcean servers and will never be shared with third-parties. Old shares will be purged form time to time. You can also delete the shared requests manually at any time.
Sometimes you might just want to link to a request on your own Clockwork instance. You will find that the request id on the bottom of the sidebar now links to the current request.
User data
While you can log anything using the rich logging capabilities or add custom timeline events, sometimes your app has a specific data you'd like to be easily accessible for each request.
With user data you can add custom data, shown as a new tab in the Clockwork app, formatted as a table or as counters (similar to performance tab).
Let's say we are building an eshop app. Instead of logging the cart contents and looking for them in the log tab, we can make a new "Cart" tab which will show some stats and the cart contents:
$cart = clock()->userData('cart')
->title('Cart');
$cart->counters([
'Products' => 3,
'Value' => '949.80€'
]);
$cart->table('Products', [
[ 'Product' => 'iPad Pro 10.5" 256G Silver', 'Price' => '849 €' ],
[ 'Product' => 'Smart Cover iPad Pro 10.5 White', 'Price' => '61.90 €' ],
[ 'Product' => 'Apple Lightning to USB 3 Camera Adapter', 'Price' => '38.90 €' ]
]);
We are using static data for demonstration, in a real implementation the data would come from a database or session based on your cart implementation.
Advanced
Authentication
Clockwork collects a lot of sensitive data. Typically you will run Clockwork only in your local development environment where this is not an issue. In some cases though, you might have a shared development or staging server.
For these situations Clockwork comes with a simple authentication using a single shared password. To use authentication, enable it and set a password in the Clockwork configuration file.
The authentication system is extensible, to see how to add your own authentication methods see the "extending authentication" section.
It is still not recommended to run Clockwork in production or environments that might contain sensitive customer data. Please make sure you understand the details of the authentication implementation if you plan to use it in a sensitive environment.
Metadata storage
Clockwork stores the collected data in a persistent manner.
The old data is automatically cleaned up after a specified cleanup interval, 30 days by default.
By default we store the metadata in a flat JSON file storage, located at storage/clockwork
. This is both simple and fast storage and doesn't require any particular PHP extensions.
Clockwork also includes an SQL storage implementation. SQL storage works great with a simple Sqlite database, but also supports MySQL and PostgreSQL. This can also be useful in a case where you need to use the collected metadata outside of Clockwork, eg. you could build an admin UI showing all requests to your application.
Another option is a Redis storage implementation, especially useful in cloud scenarios with no persistent file-system or SQL database available.
You can also extend Clockwork with your own metadata storage implementation, to learn how to do so, check out the "extending metadata storage".
Xdebug profiler
While Clockwork provides a lot of performance metrics and profiling features like timeline events, finding the problematic spot in your application can still be hard. Xdebug is a PHP extension, which provides an advanced profiler, collecting metrics about every single function call. Clockwork comes with a full-featured Xdebug profiler UI, you can find it in the performance tab.
The profiler UI will show you a breakdown of all function calls with their self and inclusive cost. You can toggle between execution time or memory usage metrics, exact or pecentual representation and of course the data is orderable and filterable.
Setup
Install the Xdebug extension via PECL (part of your PHP installation):
$ pecl install xdebug
Enable the PHP extension in your php.ini
(location of php.ini
and the xdebug extension path will depend on your operating system):
zend_extension="/usr/local/php/modules/xdebug.so"
Now we need to enable the Xdebug profiler itself. You could enable the profiling for all requests, but collecting Xdebug profiles slows down the response time dramatically. That's why it's a good idea to enable Xdebug profiling only for certain requests. To do so, add following setting to your php.ini
and you will be able to toggle whether Xdebug profiles should be collected in Clockwork profiler UI itself:
; Xdebug 3
xdebug.mode = profile
xdebug.start_with_request = trigger
xdebug.profiler_output_name = cachegrind.out.%u.%r
; Xdebug 2
xdebug.profiler_enable_trigger = 1
xdebug.profiler_output_name = cachegrind.out.%u.%r
For more detailed information about installation and other awesome Xdebug features, check out the Xdebug website.
Extending
Implementation
This section describes how Clockwork internals work. While not needed for normal usage, this can be useful if you are planning on extending Clockwork with custom data sources, storage implementations, adding more in-depth support for your custom applications or unsupported frameworks or even writing a custom Clockwork client apps.
Clockwork consists of two components:
- server-side library - responsible for collecting the data and exposing it to the clients
- client application - responsible for presenting the collected data to the user
The communication between the two components happens via a rest-like HTTP API using JSON metadata format.
Server-side library
The Clockwork server-side library consists of several components:
- DataSources - classes responsible for the metadata collection itself
- Request - data objects for storing the metadata
- Storage - classes responsible for persisting and retrieving the metadata
- Support - various supporting files for frameworks and libraries, like service providers, middleware, etc.
Clockwork also has a main Clockwork class that ties everything together and includes bunch of helper methods.
While different Clockwork integrations work in different ways a typical usage looks like this:
- a new request is received by the application
- main Clockwork class is instantiated, this automatically creates new Request instance for holding the metadata
- one or more data sources are added to the Clockwork instance via
$clockwork->addDataSource
calls
- a storage class is instantiated and set on the Clockwork instance via
$clockwork->setStorage
call
- application runs
$clockwork->resolveRequest
is called, causing Request object to pass through resolve
method on all configured data sources, each adding relevant data to the Request instance
$clockwork->storeRequest
is called, persisting the Request object via set storage implementation
X-Clockwork-Version
and X-Clockwork-Id
headers are set on the response
Check out the "extending data sources" and "extending metadata storage" for information on writing your custom data sources and storage implementations.
Metadata HTTP API
The metadata HTTP API is the glue between the server-side data collecting library and the application presenting the data. By having a well specified rest-like API we can keep different versions of the Clockwork applications and the server-side library compatible and you could event write a fully custom Clockwork application compatible with the official server-side or vice-versa.
/__clockwork/{id}
is the main and most important API endpoint. Application requests metadata about request identified by a particular ID, server-side returns the metadata in a JSON format.
While this is the only endpoint that is really required for the browser extensions to work and was the only endpoint available in the first version, there is a couple more endpoints required for various application features.
/__clockwork/latest
returns the metadata about the last executed request. Used in extension to show the last request when first time opened and required for web UI.
/__clockwork/{id}|latest/next/{limit?}
returns metadata for requests executed after request with specified ID or the latest request, with an optional limit. Required for the web UI.
/__clockwork/{id}|latest/previous/{limit?}
returns metadata for requests executed before request with specified ID or the latest request, with an optional limit. Used to load older requests in applications.
Browser extension
The browser extension checks HTTP responses for the X-Clockwork-Version
and X-Clockwork-Id
headers. The X-Clockwork-Version
header contains the version of the server-side component, while the header is required, the content is not important and is used only for new version notifications. More important is the X-Clockwork-Id
which contains the unique identifier for the current HTTP request.
Once a request containing both of these headers is received, Clockwork retrieves the request metadata via a HTTP GET request to /__clockwork/{ID}
. The metadata endpoint URI can be overridden via a X-Clockwork-Path
header, if present, the request ID will be appended to the end of the header value. This endpoint should return the request metadata in the Clockwork metadata format.
Web UI
The web UI uses the same code as the browser extension, with only difference in the metadata retrieval. As we are not running as a browser extension and can't observe all executed HTTP requests, we use ajax polling instead.
When opened, the application makes a request to the /__clockwork/latest
endpoint to load the latest request. After that we poll the /__clockwork/{id}/next
endpoint with the last request id to get all newer requests.
Data sources
Data sources are a pattern for collecting the metadata in an extensible way in the Clockwork server-side library. Each data source collects data about a particular topic, eg. a PhpDataSource, LaravelDataSource, or DoctrineDataSource.
Creating a new data source is as simple as creating a class implementing the Clockwork\DataSource\DataSourceInterface
interface. Though instead of implementing the interface we recommend extending the Clockwork\DataSource\DataSource
base class, which will make you compliant with future interface changes.
You need to implement a single resolve(Request $request)
method that will receive the Request
data object and extends it with your custom data.
For example, our application uses a custom session implementation, let's create a data source that adds the session data to Clockwork:
use Clockwork\DataSource\DataSource;
use Clockwork\Helpers\Request;
class SessionDataSource extends DataSource
{
public function resolve(Request $request)
{
$request->session = session()->all();
}
}
To use the new data source we need to register it with the main Clockwork class:
clock()->addDataSource(new SessionDataSource);
For more inspiration take a look at the existing data sources included in Clockwork.
Metadata storage
Clockwork stores the collected data in a persistent manner.
By default we use a flat JSON file storage implementation and we also include an optional SQL storage implementation. To learn how to use included implementation see the "advanced metadata storage" section.
While in most cases you will want to use one of the included options, you can write a custom one (eg. using Redis or unsupported SQL database).
To create a storage implementation you will need to implement the Clockwork\Storage\StorageInterface
interface, though it's recommended to extend the Clockwork\Storage\Storage
base class instead.
The interface contains a bunch of methods for reading requests, a save and a cleanup method. All read methods should return either single or an array of Clockwork\Helpers\Request
instances.
all()
returns all stored requests
find($id)
returns a single request with specified ID or null
latest()
returns a single latest request or null
previous($id, $count = null)
returns an array of requests received before specified ID, optionally limited to specified count
next($id, $count = null)
returns an array of requests received after specified ID, optionally limited to specified count
store(Request $request)
store the request
cleanup()
clean up old requests, the algorithm is up to you
To use the custom storage implementation we need to set it on the main Clockwork class:
clock()->setStorage(new RedisStorage);
Feel free to take a look at existing storage implementations for inspiration.
Authentication
The authentication in Clockwork works very simple. Each metadata request contains an authentication token, which is passed to the authenticator to decide whether we should return the metadata. If the Clockwork app receives a forbidden response, it will assume an authentication is required and asks for username, password or both as required by the authenticator. Submitting this form will make an authentication attempt on authenticator which will return a new authentication token when successful.
To create an authenticator implementation you will need to implement the Clockwork\Authentication\AuthenticatorInterface
interface.
attempt(array $credentials)
receives an array of credentials (username
, password
or both), if the credentials are valid, returns an authentication token, returns null for invalid credentials
check($token)
receives an authentication token, returns true if the token is valid
requires()
returns an array of required credentials, this will be either AuthenticatorInterface::REQUIRES_USERNAME
or AuthenticatorInterface::REQUIRES_PASSWORD
, the Clockwork app will then show one or both fields
To use the custom authenticator we need to set it on the main Clockwork class:
clock()->setAuthenticator(new EloquentAuthenticator);
Feel free to take a look at existing authenticator implementations for inspiration.
Extensions
Here you can find various 3rd party extensions, clients and projects with Clockwork support.
Clockwork libraries
Clockwork clients
Alternative implementations
Projects with Clockwork support
- Laravel Debugbar - integrates PHP Debug Bar for Laravel, includes Clockwork support
- Laravel Doctrine - a drop-in Doctrine2 implementation for Laravel 5+, includes Clockwork support
Did you make your own Clockwork related project? Let us know at info@underground.works.
Privacy
Installation and some updates of the Clockwork browser extension require some privacy permissions.
Since our browsers handle a lot of personal information, we feel it's important to explain what we can do with each permission and why do we need them.
Permission to "Read your browsing history"
Clockwork uses the webNavigation
API, used to detect navigation events, eg. entering URLs to address bar, clicking links, etc.
Used for the preserve log feature. When preserve log is off, we use this API to know when to clear the requests list.
Clockwork also uses the tabs
API, used for interacting with open browser tabs.
Used for retrieving current page URL required for setting up metadata requests and Xdebug profiler cookies.
Permission to "Read and change all your data on the websites you visit"
Clockwork uses the webRequest
API, used for observing HTTP requests made by the browser, including submitted data, URLs, full response content, with ability to block or modify these requests.
Used for observing incoming HTTP requests for Clockwork-enabled applications and loading Clockwork metadata from headers.
We immediately disregard any requests to non Clockwork-enabled applications, we never modify or store requests.
The extension available in the Chrome Web Store or Firefox Addons is always the latest tagged commit with no modifications.
FAQ
This error message is shown when we can't load metadata for the selected request. This can be caused by several reasons, depending on the error message:
This can be caused by a network error, misconfigured web server or an invalid SSL certificate.
This message is shown when the network request, to fetch the metadata, failed before reaching your PHP application. Some of the common cases:
- Low-level networking or connection error.
- Misconfigured web-server not being able to accept the connection.
- Invalid SSL certificate in case of using HTTPS. (Required in Chrome Extension.)
Note, Chrome recently broke extensions making requests to HTTPS sites using self-signed certificates, if this affects you, you can +1 this issue - https://issues.chromium.org/issues/40882068.
Server returned an error response.
This message is shown when the network request reached your PHP application, but it crashed and returned HTTP 500 error. Please check your application logs for more details.
Server returned an empty metadata.
This message is shown when we got a HTTP response back from our application, but it did not contain valid Clockwork data. Please check if Clockwork is properly installed and configured.
Clockwork doesn't work when using the "dd" function in Laravel
That's to be expected, the "dd" function calls the die()
php function, which immediately stops the script execution, so Clockwork has no chance to finish processing the request correctly.