Zipkin PHP is the official PHP Tracer implementation for Zipkin

Last update: May 14, 2022

Zipkin PHP

CI Latest Stable Version Coverage Status Minimum PHP Version Total Downloads License

Zipkin PHP is the official PHP Tracer implementation for Zipkin, supported by the OpenZipkin community.

Installation

composer require openzipkin/zipkin

Setup

use Zipkin\Annotation;
use Zipkin\Endpoint;
use Zipkin\Samplers\BinarySampler;
use Zipkin\TracingBuilder;
use Zipkin\Reporters\Http;

// First we create the endpoint that describes our service
$endpoint = Endpoint::create('my_service');

$reporter = new Http(['endpoint_url' => 'http://myzipkin:9411/api/v2/spans']);
$sampler = BinarySampler::createAsAlwaysSample();
$tracing = TracingBuilder::create()
    ->havingLocalEndpoint($endpoint)
    ->havingSampler($sampler)
    ->havingReporter($reporter)
    ->build();

$tracer = $tracing->getTracer();

...

$tracer->flush();

Obs. for a more complete frontend/backend example, check this repository.

Tracing

The tracer creates and joins spans that model the latency of potentially distributed work. It can employ sampling to reduce overhead in process or to reduce the amount of data sent to Zipkin.

Spans returned by a tracer report data to Zipkin when finished, or do nothing if unsampled. After starting a span, you can annotate events of interest or add tags containing details or lookup keys.

Spans have a context which includes trace identifiers that place it at the correct spot in the tree representing the distributed operation.

Local Tracing

When tracing local code, just run it inside a span

$span = $tracer->newTrace();
$span->setName('encode');
$span->start();

try {
  doSomethingExpensive();
} finally {
  $span->finish();
}

In the above example, the span is the root of the trace. In many cases, you will be a part of an existing trace. When this is the case, call newChild instead of newTrace

$span = $tracer->newChild($root->getContext());
$span->setName('encode');
$span->start();
try {
  doSomethingExpensive();
} finally {
  $span->finish();
}

Customizing spans

Once you have a span, you can add tags to it, which can be used as lookup keys or details. For example, you might add a tag with your runtime version.

$span->tag('http.status_code', '200');

RPC tracing

RPC tracing is often done automatically by interceptors. Under the scenes, they add tags and events that relate to their role in an RPC operation.

Here's an example of a client span:

// before you send a request, add metadata that describes the operation
$span = $tracer->newTrace();
$span->setName('get');
$span->setKind(Kind\CLIENT);
$span->tag('http.status_code', '200');
$span->tag(Tags\HTTP_PATH, '/api');
$span->setRemoteEndpoint(Endpoint::create('backend', 127 << 24 | 1, null, 8080));

// when the request is scheduled, start the span
$span->start();

// if you have callbacks for when data is on the wire, note those events
$span->annotate(Annotation\WIRE_SEND);
$span->annotate(Annotation\WIRE_RECV);

// when the response is complete, finish the span
$span->finish();

Sampling

Sampling may be employed to reduce the data collected and reported out of process. When a span isn't sampled, it adds no overhead (noop).

Sampling is an up-front decision, meaning that the decision to report data is made at the first operation in a trace, and that decision is propagated downstream.

By default, there's a global sampler that applies a single rate to all traced operations. Sampler is how you indicate this, and it defaults to trace every request.

Custom sampling

You may want to apply different policies depending on what the operation is. For example, you might not want to trace requests to static resources such as images, or you might want to trace all requests to a new api.

Most users will use a framework interceptor which automates this sort of policy. Here's how they might work internally.

private function newTrace(Request $request) {
  $flags = SamplingFlags::createAsEmpty();
  if (strpos($request->getUri(), '/experimental') === 0) {
    $flags = DefaultSamplingFlags::createAsSampled();
  } else if (strpos($request->getUri(), '/static') === 0) {
    $flags = DefaultSamplingFlags::createAsSampled();
  }
  return $tracer->newTrace($flags);
}

Propagation

Propagation is needed to ensure activity originating from the same root are collected together in the same trace. The most common propagation approach is to copy a trace context from a client sending an RPC request to a server receiving it.

For example, when an downstream Http call is made, its trace context is sent along with it, encoded as request headers:

   Client Span                                                Server Span
┌──────────────────┐                                       ┌──────────────────┐
│                  │                                       │                  │
│   TraceContext   │           Http Request Headers        │   TraceContext   │
│ ┌──────────────┐ │          ┌───────────────────┐        │ ┌──────────────┐ │
│ │ TraceId      │ │          │ X-B3-TraceId      │        │ │ TraceId      │ │
│ │              │ │          │                   │        │ │              │ │
│ │ ParentSpanId │ │ Extract  │ X-B3-ParentSpanId │ Inject │ │ ParentSpanId │ │
│ │              ├─┼─────────>│                   ├────────┼>│              │ │
│ │ SpanId       │ │          │ X-B3-SpanId       │        │ │ SpanId       │ │
│ │              │ │          │                   │        │ │              │ │
│ │ Sampled      │ │          │ X-B3-Sampled      │        │ │ Sampled      │ │
│ └──────────────┘ │          └───────────────────┘        │ └──────────────┘ │
│                  │                                       │                  │
└──────────────────┘                                       └──────────────────┘

The names above are from B3 Propagation, which is built-in to Brave and has implementations in many languages and frameworks.

Most users will use a framework interceptor which automates propagation. Here's how they might work internally.

Here's what client-side propagation might look like

// configure a function that injects a trace context into a request
$injector = $tracing->getPropagation()->getInjector(new RequestHeaders);

// before a request is sent, add the current span's context to it
$injector($span->getContext(), $request);

Here's what server-side propagation might look like

// configure a function that extracts the trace context from a request
$extractor = $tracing->getPropagation()->getExtractor(new RequestHeaders);
$extracted = $extractor($request);

$span = $tracer->newChild($extracted);
$span->setKind(Kind\SERVER);

If you aren't using a framework or don't have access to the Request object, you can extract the context from the $_SERVER variable

$extractor = $tracing->getPropagation()->getExtractor(new ServerHeaders);
$extracted = $extractor($_SERVER);

Extracting a propagated context

The Extractor reads trace identifiers and sampling status from an incoming request or message. The carrier is usually a request object or headers.

SamplingFlags|TraceContext is usually only used with $tracer->newChild(extracted), unless you are sharing span IDs between a client and a server.

Implementing Propagation

Extractor will output a SamplingFlags|TraceContext with one of the following:

  • TraceContext if trace and span IDs were present.
  • SamplingFlags if no identifiers were present

Current Span

Zipkin supports a "current span" concept which represents the in-flight operation. Tracer::currentSpan() can be used to add custom tags to a span and Tracer::nextSpan() can be used to create a child of whatever is in-flight.

A common use case for the current span is to instrument RPC clients. For example:

/**
  * This http clients composes an http client using PSR7
  */
class TraceClient implements ClientInterface
{
    public function request($method, $uri = '', array $options = [])
    {
        /* Gets the child Span of the current one */
        $span = $this->tracer->nextSpan();
        $span->setKind(Zipkin\Kind\CLIENT);
        $span->tag(Tags\HTTP_PATH, $uri);

        try {
            $response = $this->client->request($method, $uri, $options);
            $span->tag(Tags\HTTP_STATUS_CODE, $response->getStatusCode());

            return $response;
        catch (Throwable $e) {
            $span->setError($e);
            throw $e;
        } finally {
            $span->finish();
        }
    }
}

Setting a span in scope manually

When writing new instrumentation, it is important to place a span you created in scope as the current span.

In edge cases, you may need to clear the current span temporarily. For example, launching a task that should not be associated with the current request. To do this, simply pass null to openScope.

Instrumentation

Tests

Tests can be run by

composer test

Whereas static checks can be run by:

composer static-check

Reference

GitHub

https://github.com/openzipkin/zipkin-php
Comments
  • 1. Explore possibilities for bulk reporting

    At the moment, every trace (a set of spans) from a request will end up being one http request to the reporter. This is not ideal but limitation in the language as PHP is, in many real-world contexts, single-threaded and does not have an event loop like Node.js so we must flush when the request finishes. This is something convenient at small scale but not much at a big scale. As the outcome of this issue we should come up with a solution to avoid the overhead on the immediate reporter vs. bulk reporter.

    Ping @adriancole @basvanbeek @beberlei @felixfbecker

    Reviewed by jcchavezs at 2017-10-27 14:57
  • 2. Support for PHP 8.0

    Hi,

    I've noticed that there are 2 PR's already on this topic (#200 and #198 ), so I thought it might be ok to also have an issue about the challenges around this. Also being selfish and all I was hit by the incompatibility with PHP 8 as we're going through a migration process with a couple of projects that also use zipkin.

    Given that both PHP 7.1 & PHP 7.2 are past their EOL dates, is there a support target/plan with respect to backwards compatibility of various PHP versions?

    Thanks

    Reviewed by andrei-dascalu at 2021-05-26 19:49
  • 3. Add Memcached Reporter

    This PR adds memcached reporter. So basically it is similar to InMemory but it stores the value in a memcached server. It also should work as expected in case of concurrent reads and writes. it uses this feature from memcached https://www.php.net/manual/en/memcached.cas.php. This requires php-memcached extension, so it will be a breaking change.

    Usage

    In application, we use Memcached reporter not HTTP reporter.

    <?php
    // app.php
    include_once dirname(__FILE__) . "/vendor/autoload.php";
    
    use Zipkin\Annotation;
    use Zipkin\Endpoint;
    use Zipkin\Samplers\BinarySampler;
    use Zipkin\TracingBuilder;
    use Zipkin\Reporters\Aggregation\MemcachedClient;
    use Zipkin\Reporters\Memcached;
    
    $endpoint = Endpoint::create('clivern');
    
    $reporter = new Memcached([], new MemcachedClient('127.0.0.1'));
    
    $sampler = BinarySampler::createAsAlwaysSample();
    $tracing = TracingBuilder::create()
        ->havingLocalEndpoint($endpoint)
        ->havingSampler($sampler)
        ->havingReporter($reporter)
        ->build();
    
    $tracer = $tracing->getTracer();
    
    for ($i=1; $i <= 10000; $i++) {
      $span = $tracer->newTrace();
      $span->setName(sprintf("span_%d", $i));
      $span->start();
    
      try {
        // something quite fast
        var_dump("test");
      } finally {
        $span->finish();
      }
    
      $tracer->flush();
    }
    

    Then we create a cron job or a command to read from Memcached reporter and send to Zipkin using HTTP reporter. We may even add this as application middleware with a time interval.

    <?php
    // daemon.php
    include_once dirname(__FILE__) . "/vendor/autoload.php";
    
    use Zipkin\Reporters\Aggregation\MemcachedClient;
    use Zipkin\Reporters\Memcached;
    use Zipkin\Reporters\Http;
    
    $reporter = new Memcached([], new MemcachedClient('127.0.0.1'));
    $httpReporter = new Http(['endpoint_url' => 'http://zipkin.local:9411/api/v2/spans']);
    
    while (true) {
        $spans = $reporter->flush();
    
        if (!empty($spans)){
            $httpReporter->report($spans);
        }
    
        sleep(5);
    }
    

    Flushing can be based on a time interval or the stored value size (Memcached support value up to 1MB by default that's ~1000000 chars). i didn't add any implementation since it is totally up to the developer and the scale zipkin is used. reporting 2 spans/second will have a different implementation than 1000 spans/second and I think this shouldn't be part of the package. in case you will hit the 1MB size limit in a second, you can either increase memcached maximum object size or report with different memcached keys, so basically you split the collected spans across different memcached keys to get more space before flushing.

    Please let me know if something need to be adjusted!

    Fix #22

    Update:

    To run as single process

    <?php
    
    include_once dirname(__FILE__) . "/vendor/autoload.php";
    
    use Zipkin\Annotation;
    use Zipkin\Endpoint;
    use Zipkin\Samplers\BinarySampler;
    use Zipkin\TracingBuilder;
    use Zipkin\Reporters\Aggregation\MemcachedClient;
    use Zipkin\Reporters\Memcached;
    use Zipkin\Reporters\Http;
    
    
    $endpoint = Endpoint::create('orders_service');
    
    $httpReporter = new Http([
      'endpoint_url' => 'http://zipkin.local:9411/api/v2/spans'
    ]);
    
    $reporter = new Memcached(
        [],
        $httpReporter,
        new MemcachedClient('127.0.0.1')
    );
    
    $sampler = BinarySampler::createAsAlwaysSample();
    $tracing = TracingBuilder::create()
        ->havingLocalEndpoint($endpoint)
        ->havingSampler($sampler)
        ->havingReporter($reporter)
        ->build();
    
    $tracer = $tracing->getTracer();
    
    for ($i=1; $i <= 400; $i++) {
      $span = $tracer->newTrace();
      $span->setName(sprintf("span_%d", $i));
      $span->start();
    
      try {
        var_dump("report");
      } finally {
        $span->finish();
      }
    
      $tracer->flush();
    }
    
    Reviewed by Clivern at 2021-06-09 21:28
  • 4. Allow using custom Recorder and add option to always record spans

    This will let me implement "firehose mode", similar to what we have in py_zipkin.

    Basically what I need is a way to call 2 different Reporters:

    • one gets called only when sampled is True
    • one gets called every time (this is the firehose recorder) This cannot be accomplished with just one Reporter, because once we're inside the reporter we've lost any info on whether the trace was sampled or not.

    I can almost do this in zipkin-php, there are only 2 things missing.

    • if sampled is False, we create a NoopSpan. So I need an extra flag to inform the tracer that I always want to create a RealSpan
    • the Recorder is hardcoded inside the Tracer class, so I cannot pass my own.

    Once those 2 things are supported, I can write my own Recorder subclass that calls the right Reporters as needed with minimal changes to the core zipkin-php code.

    cc @adriancole

    Reviewed by drolando at 2020-06-13 02:22
  • 5. Enhancement: Normalize composer.json

    This PR

    • [x] normalizes composer.json

    💁‍♂️ I ran

    $ composer global require localheinz/composer-normalize
    

    followed by

    $ composer normalize
    

    For reference, see https://github.com/localheinz/composer-normalize.

    Reviewed by localheinz at 2018-07-14 06:42
  • 6. PHP 8: upgrade middlewares, phpunit and replace guzzle psr7 with nyholm

    Proposal for issue #202

    • there was a bit of a snowball there with respect to aligning dependencies to work with minor PHP versions (I did not try too hard to find a way to keep 7.2 as per issue comments).
    • See https://github.com/php-http/discovery/issues/164 - guzzlehttp doesn't provide expected PSR-17 factories (there's code available ready for their v2, but that would mean dropping some stability constraints) => switched to nyholm (it claims some performance boost as well, though probably not too relevant since we're talking tests)
    • some tweaks around the tests: eg dechex() needs an int, but hexdec() returns int|float, running afoul of strong type check.
    • updated phpunit also due to version constraints (phpunit 8 was still complaining about running on php 8) which led to lots of warnings about prophecy having to use a trait for integration with phpunit (could ignore those I guess to aim for 7.2 compatibility), which requires phpspec/prophecy-phpunit which in turn requires min. 7.3
    • rename class that did not conform to PSR-4
    Reviewed by andrei-dascalu at 2021-05-26 22:15
  • 7. Add inSpan method for tracer

    Sometimes you need to instrument operations that are being performed by legacy code. E.g. http call to a service but instead of using a http standard library like guzzle, it is being done with raw curl. Those times, the effort to actually replace the curl call and use a new shiny and instrumented library like guzzle is already a big effort and it is very error prone.

    In those cases, having a Tracer::inSpan($options, $callable, $args) method would be helpful as that method is going to do tracing around that legacy call without forcing you to touch the logic (more than passing the right variables into the callable). Does that sound a reasonable use case?

    Initial feedback from @adriancole:

    I think there have been similar discussions around this.. sleuth has the ability to do this also py_zipkin. to a degree zipkin-js does (promise tracing)

    Ping @adriancole @basvanbeek

    Reviewed by jcchavezs at 2019-07-03 08:49
  • 8. Http Reporter always calling http://localhost

    Hello,

    While trying to use zipkin-php in a docker-compose context, I found that traces sent to a zipkin server running inside compose network from a php script also running in compose would not be picked up, whereas the same script sent from local machine to the same zipkin (but running with exposed port 9411) would work ok.

    I found that:

    • as per zipkin-php-example code, simply creating the endpoint with $endpoint = Endpoint::create($endpointName, $ipv4, null, $port); doesn't have an impact on where the HttpReporter makes api calls (I would be expecting it calls a server found at $ipv4 ip)
    • passing an options array specifying the url to the Http reporter constructor works (endpoint_url key)

    How create_tracing method looks now:

    $endpoint = Endpoint::create($endpointName, $ipv4, null, $port); $http = \Zipkin\Reporters\Http\CurlFactory::create(); $reporter = new Zipkin\Reporters\Http($http, [ 'endpoint_url' => sprintf('http://%s:%s/api/v2/spans', $ipv4, $port) ]); $sampler = BinarySampler::createAsAlwaysSample(); $tracing = TracingBuilder::create() ->havingLocalEndpoint($endpoint) ->havingSampler($sampler) ->havingReporter($reporter) ->build();

    I'm not entirely sure whether my understanding is completely off (eg: is the $ipv4 where api calls should be made?) or whether this is a bug and what would be a way to handle it.

    I believe at the very least the docs should reflect this.

    Cheers

    Reviewed by andrei-dascalu at 2019-05-18 05:11
  • 9. Reporter silent error handling

    Currently it is hard to debug/understand when our spans are not accepted by the zipkin Server.

    For instance my Zipkin client was sending a null value in a tag by doing $span->tag('curl.total_time', $info['total_time']); //total_time was null

    Zipkin Server response was 400 but that was hidden from me because of the try/catch block here https://github.com/openzipkin/zipkin-php/blob/master/src/Zipkin/Reporters/Http.php#L63

    I suggest adding Debug mode or Verbosity config to the client so that we know when things start failing for some reason.

    Reviewed by telemmaite at 2018-10-10 12:55
  • 10. Allow a timeout value to be set on the cURL Call.

    Generally speaking, the Zipkin reporting call should be non-blocking and asynchronous. But since PHP almost doesn't have either of these properties, it's good to at least be sure that reporting of the Zipkin Trace is not causing a major delay in sampled traces.

    Closes #94

    Reviewed by Aideen-Nasirishargh-CK at 2018-10-05 00:52
  • 11. [#27] Removes dependency on guzzle.

    This PR removes the dependency on the guzzle client using curl by default. The factory interface allows users to create their own clients tho.

    Ping @beberlei @felixfbecker @cc5092

    Closes #27

    Reviewed by jcchavezs at 2017-12-29 14:42
  • 12. The field for Log Events cannot be set(key)

                $span->log([
                    'event'=>'error',
                    'stack'=> (string)$exception,
                ]);
    

    image

    event and stack valid

    Reviewed by tw2066 at 2022-03-28 08:27
  • 13. Calculate number of messages and message size among microservices

    Hello everyone,

    I have a php app which communicates with other microservices for its operations.

    Can i use Zipkin to observe every message between microservices and their size?

    Essentially, i need to have a clear picture for the affinities between the microservices of my architecture.

    How can i do it?

    Reviewed by ktsakos at 2021-01-11 15:18
  • 14. Make CI use script based convention used in other projects

    If you don't mind, please move some of the logic inlined into ci.yml into build-bin, with a README and RELEASE.md like the other projects. Also, if you can, please change the GH actions file and job names so that they are basically the same (makes badges easier also).

    Here's a couple examples:

    • https://github.com/openzipkin/zipkin-ruby/pull/180
    • https://github.com/openzipkin/zipkin-api

    Motivation

    We are standardizing build script and job names for easy reference when people switch from one project to another. It is important that the tasks done in CI do not heavily rely on CI specific tools as in the future we may get into trouble like this again. For example, in the past we had to switch from travis to circle back to travis. Using scripts we control as entrypoints gives us flexibility as CI providers change their policies around open source communities.

    Reviewed by codefromthecrypt at 2020-11-26 02:20
  • 15. Reporter can't provide feedback on success

    Currently reporter is not providing any feedback about the call to the zipkin server, if it fails it logs the error and don't fail and more so if it success, it won't notify the user about it.

    This is alright in normal situations but can be a bit obscure in tooling, for example: https://github.com/jcchavezs/jaeger2zipkin/blob/master/Main.php#L53

    One option is to add a debug log line on success. Any ideas @anuraaga @adriancole @basvanbeek ?

    Reviewed by jcchavezs at 2020-10-24 18:14
  • 16. Map is already too complicated

    Initially Map was a Getter/Setter supposed to act as a usual map (i.e. set/get by key, see https://github.com/openzipkin/zipkin-php/blob/master/src/Zipkin/Propagation/Map.php), unfortunately I also promoted its use for HTTP headers (for things like Symfony) and that is how Map also supported case insensitiviness and array access.

    Nowadays the lesson learnt is that each different Getter/Setter format deserve its own implementation rather than trying to reuse Map and hence to not add crap into existing abstractions. We can't change Map to be simpler now but we can create a very simple class for a truly simple map and use for the messaging abstraction (and deprecate Map), not sure how to call it tho:

    • SimpleMap
    • Array
    • ?

    Any idea @adriancole @anuraaga

    Reviewed by jcchavezs at 2020-09-07 09:01
PHP APM (Alternative PHP Monitor)

APM (Alternative PHP Monitor) APM (Alternative PHP Monitor) is a monitoring extension enabling native Application Performance Management (APM) for PHP

May 19, 2022
Debug bar for PHP
Debug bar for PHP

PHP Debug Bar Displays a debug bar in the browser with information from php. No more var_dump() in your code! Features: Generic debug bar Easy to inte

May 11, 2022
Xdebug — Step Debugger and Debugging Aid for PHP

Xdebug Xdebug is a debugging tool for PHP. It provides step-debugging and a whole range of development aids, such as stack traces, a code profiler, fe

May 13, 2022
Kint - a powerful and modern PHP debugging tool.
Kint - a powerful and modern PHP debugging tool.

Kint - debugging helper for PHP developers What am I looking at? At first glance Kint is just a pretty replacement for var_dump(), print_r() and debug

May 14, 2022
😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.
😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.

Tracy - PHP debugger Introduction Tracy library is a useful helper for everyday PHP programmers. It helps you to: quickly detect and correct errors lo

May 20, 2022
PHP Benchmarking framework
PHP Benchmarking framework

PHPBench is a benchmark runner for PHP analogous to PHPUnit but for performance rather than correctness. Features include: Revolutions: Repeat your co

May 22, 2022
The Interactive PHP Debugger

The interactive PHP debugger Implemented as a SAPI module, phpdbg can exert complete control over the environment without impacting the functionality

Apr 26, 2022
Dontbug is a reverse debugger for PHP
Dontbug is a reverse debugger for PHP

Dontbug Debugger Dontbug is a reverse debugger (aka time travel debugger) for PHP. It allows you to record the execution of PHP scripts (in command li

May 8, 2022
PHP Debug Console
PHP Debug Console

PHP Console A web console to try your PHP code into Creating a test file or using php's interactive mode can be a bit cumbersome to try random php sni

May 14, 2022
Php Debugger to run in terminal to debug your code easily.
Php Debugger to run in terminal to debug your code easily.

What is Dephpugger? Dephpugger (read depugger) is an open source lib to make a debug in php direct in terminal, without necessary configure an IDE. Th

Jan 12, 2022
PCOV - CodeCoverage compatible driver for PHP

PCOV A self contained CodeCoverage compatible driver for PHP Requirements and Installation See INSTALL.md API /** * Shall start recording coverage in

May 6, 2022
Low-overhead sampling profiler for PHP 7+
Low-overhead sampling profiler for PHP 7+

phpspy phpspy is a low-overhead sampling profiler for PHP. For now, it works with Linux 3.2+ x86_64 non-ZTS PHP 7.0+ with CLI, Apache, and FPM SAPIs.

May 14, 2022
The VarDumper component provides mechanisms for walking through any arbitrary PHP variable. It provides a better dump() function that you can use instead of var_dump().

VarDumper Component The VarDumper component provides mechanisms for walking through any arbitrary PHP variable. It provides a better dump() function t

May 18, 2022
PHP errors for cool kids
PHP errors for cool kids

whoops PHP errors for cool kids whoops is an error handler framework for PHP. Out-of-the-box, it provides a pretty error interface that helps you debu

May 18, 2022
Clockwork - php dev tools in your browser - server-side component
Clockwork - php dev tools in your browser - server-side component

Clockwork is a development tool for PHP available right in your browser. Clockwork gives you an insight into your application runtime - including requ

May 18, 2022
Laravel Debugbar (Integrates PHP Debug Bar)
Laravel Debugbar (Integrates PHP Debug Bar)

Laravel Debugbar This is a package to integrate PHP Debug Bar with Laravel. It includes a ServiceProvider to register the debugbar and attach it to th

May 24, 2022
This package connects a Laravel Octance application with Tideways for PHP Monitoring, Profiling and Exception Tracking.

Tideways Middleware for Laravel Octane This package connects a Laravel Octance application with Tideways for PHP Monitoring, Profiling and Exception T

Jan 6, 2022
A tool to profile mysql queries in php env.
A tool to profile mysql queries in php env.

MysqlQueryProfiler This tool helps you to quickly profile a mysql query in a PHP 7.4+ environnement. You can also compare 2 queries. This image shows

Jul 30, 2021
Datadog Tracing PHP Client

DD Trace PHP PHP Tracer Getting Started The Datadog PHP Tracer (ddtrace) brings APM and distributed tracing to PHP. Installing the extension Visit the

May 24, 2022