18

Clockwork

 6 years ago
source link: https://underground.works/clockwork/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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.

Vanilla

Install the Clockwork library via Composer.

$ composer require itsgoingd/clockwork

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->returnMetadata();

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.

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.

Install the Clockwork library via Composer.

$ composer require itsgoingd/clockwork

Once Clockwork is installed, you'll need to add the Slim middleware to your app, specifying the path for the Clockwork metadata:

$app = AppFactory::create(); $app->add(new Clockwork\Support\Slim\ClockworkMiddleware($app, __DIR__ . '/storage/clockwork'));

Slim 3 is also supported:

$app = new Slim\App(...); $app->add(new Clockwork\Support\Slim\Legacy\ClockworkMiddleware(__DIR__ . '/storage/clockwork'));

Slim 2 is also supported:

$app = new Slim(...); $app->add(new Clockwork\Support\Slim\Old\ClockworkMiddleware(__DIR__ . '/storage/clockwork'));

Upgrade guide

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 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 testing setup. This is disabled by default and needs to be enabled in the config file.

To collect data about ran 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:

clockwork.png

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.

toolbar.png

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.

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 2 xdebug.profiler_enable_trigger = 1

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 extensions

Clockwork clients

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 [email protected].

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.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK