Add Custom Timespans to Timeline

There are three APIs to collect additional timespans from your application to feed into the Timeline Profiler.

#[WithSpan] attribute on functions and methods

Available since Tideways PHP Extension 5.6.4 or later.

By adding a PHP 8 attribute #[WithSpan] to a userland function or method you can directly create a span that represents the function call. This is useful on functions and methods that are called only a few times each request and signify which high-level / service-level algorithms take the most time during the request.

<?php

namespace App\Model;

use Tideways\Profiler\WithSpan;

class RegistrationService
{
    #[WithSpan]
    public function registerNewUser(array $data): User
    {
    }

    #[WithSpan]
    public function sendRegistrationEmail(User $user)
    {
    }
}

We recommend to put them on services and functions that are called either directly from the controller or just a level below in a service.

Using the attribute is safe even when the "tideways" extension is not installed, because PHP does not require the attribute class to be present. However note that individual frameworks could potentially force the loading of attributes via the autoloader.

Explicitly create, start and stop timespans

Tideways collects a single root timespan for every request by default. These time spans are used to calculate the response time charts. You can add more spans to a trace that represent SQL, HTTP or any other kind of operation and see a full trace timeline inside the Tideways UI.

This is the code to create spans during PHP requests which you want to trace:

<?php

function insertUser($name) {
    // this span represents the insertUser function, being the parent for two sql statements
    $span = \Tideways\Profiler::createSpan('php');
    $span->annotate(['title' => 'insertUsers']);

    try {
        $stmt = $pdo->prepare('INSERT INTO users (name) values (?)');
        $stmt->bindValue(1, $name);
        $stmt->execute();

        $id = $pdo->lastInsertId();
        $stmt = $pdo->prepare('INSERT INTO users_log (user_id, message, log_date) VALUES (?, ?, NOW())');
        $stmt->bindValue(1, $id);
        $stmt->bindValue(2, 'User with name ' . $name . ' created.');
        $stmt->execute();
    } finally {
        $span->finish();
    }
}

To avoid cluttering your codebase with Tideways Span code you should integrate this deep into your libraries and abstractions for database and HTTP clients.

Annotations are key/value pairs of additional information that we can display in the Tideways UI for each span.

Watching Function Calls

Sometimes you can’t or want to deeply integrate into a library. The Tideways extension offers a simple method to wrap spans around function calls by calling the method watch():

<?php

\Tideways\Profiler::start();
\Tideways\Profiler::watch('Acme\Library::doSomething');
Watches are only triggered in Tracing mode of Tideways and not in monitoring mode.

Watching function calls with callback

If you have more special needs there is a more powerful function that allows creating spans using a PHP callback:

<?php

\Tideways\Profiler::start();
\Tideways\Profiler::watchCallback(
    'MyTemplateEngine::render',
    function($context) {
        $span = \Tideways\Profiler::createSpan('view');

        $templateName = $context['object']->getTemplateName();
        $span->annotate(['title' => $templateName]);

        return $span;
    }
);

The $context variable has the following keys:

  • $context['fn'] contains the string of the function being called, in the above example MyTemplateEngine::render.

  • $context['object'] is set to the current instance where the method is being called on.

  • $context['args'] contains a list of arguments passed to the called function.

Watches are only triggered in Tracing mode of Tideways and not in monitoring mode. Using a watch callback to set the transaction or service name is therefore not reliable.
Still need help? Email [email protected]