PHPackages                             kaz29/cakephp-otel-plugin - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. kaz29/cakephp-otel-plugin

ActiveCakephp-plugin[Utility &amp; Helpers](/categories/utility)

kaz29/cakephp-otel-plugin
=========================

OpenTelemetry instrumentation plugin for CakePHP

0.0.4(1mo ago)0129—2.5%[2 PRs](https://github.com/kaz29/cakephp-otel-plugin/pulls)MITPHPPHP ^8.1CI passing

Since Mar 28Pushed 3w agoCompare

[ Source](https://github.com/kaz29/cakephp-otel-plugin)[ Packagist](https://packagist.org/packages/kaz29/cakephp-otel-plugin)[ RSS](/packages/kaz29-cakephp-otel-plugin/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (3)Dependencies (12)Versions (9)Used By (0)

CakePHP OpenTelemetry Plugin
============================

[](#cakephp-opentelemetry-plugin)

[![Tests](https://github.com/kaz29/cakephp-otel-plugin/actions/workflows/tests.yml/badge.svg)](https://github.com/kaz29/cakephp-otel-plugin/actions/workflows/tests.yml)

[日本語版🇯🇵](README.ja.md)

A CakePHP 5 plugin that adds OpenTelemetry instrumentation to your application. It uses `ext-opentelemetry`'s `zend_observer` hooks to automatically generate spans for Controller and Table operations without any code changes.

Requirements
------------

[](#requirements)

- PHP 8.3+
- CakePHP 5.x
- `ext-opentelemetry` PECL extension

Installation
------------

[](#installation)

```
composer require kaz29/cakephp-otel-plugin
```

Load the plugin in `config/bootstrap.php` or `Application::bootstrap()`:

```
$this->addPlugin('OtelInstrumentation');
```

Instrumented Targets
--------------------

[](#instrumented-targets)

TargetSpan name example`Controller::invokeAction``App\Controller\UsersController::index``Table::find``Users.find(all)``Table::save``Users.save``Table::delete``Users.delete`Excluding Instrumentation
-------------------------

[](#excluding-instrumentation)

Some endpoints — health checks called every few seconds by load balancers and orchestrators, for example — generate high volumes of low-value spans that bloat your telemetry backend. You can opt out specific Controller/action pairs from instrumentation:

```
// config/bootstrap.php or config/app_local.php
use Cake\Core\Configure;

Configure::write('OtelInstrumentation.exclude', [
    // Skip every action on HealthController (health/readiness/liveness probes)
    ['controller' => \App\Controller\HealthController::class, 'action' => '*'],

    // Skip a specific action while leaving others instrumented
    ['controller' => \App\Controller\PostsController::class, 'action' => 'ping'],
]);
```

Matching is **exact** — `controller` must be the fully-qualified class name and `action` must match the action name verbatim. The single exception is `'action' => '*'`, which matches every action of that controller. `'*'` is not allowed on `controller`.

While an excluded action is executing, **child Table::find/save/delete calls and custom-hook spans are also suppressed**, so a single rule cleans up the whole subtree. Once the action returns, instrumentation resumes for subsequent requests.

This setting only affects HTTP requests dispatched through `Controller::invokeAction`. CLI commands are not instrumented in the first place.

Custom Instrumentation
----------------------

[](#custom-instrumentation)

You can instrument any class method by registering custom hooks. The plugin uses the same `\OpenTelemetry\Instrumentation\hook()` mechanism as the built-in Controller/Table instrumentation.

> **Note:** `Controller::invokeAction`, `Table::find`, `Table::save`, and `Table::delete` are already instrumented by the plugin. Do not register them as custom hooks — doing so would create duplicate spans.

### Via Configure (simple)

[](#via-configure-simple)

```
// config/bootstrap.php or config/app_local.php
use Cake\Core\Configure;
use OpenTelemetry\API\Trace\SpanKind;

Configure::write('OtelInstrumentation.hooks', [
    // Minimal — span name auto-generated as "App\Service\PaymentService::charge"
    ['class' => \App\Service\PaymentService::class, 'method' => 'charge'],

    // With options
    [
        'class' => \App\Service\PaymentService::class,
        'method' => 'refund',
        'spanName' => 'payment.refund',
        'kind' => SpanKind::KIND_CLIENT,
        'attributes' => ['payment.provider' => 'stripe'],
    ],
]);
```

### Via static registration (advanced)

[](#via-static-registration-advanced)

Use `CustomInstrumentation::register()` when you need dynamic attributes via callback:

```
// In Application::bootstrap(), before $this->addPlugin('OtelInstrumentation')
use OtelInstrumentation\Instrumentation\CustomInstrumentation;
use OpenTelemetry\API\Trace\SpanKind;

CustomInstrumentation::register(
    \App\Service\PaymentService::class,
    'charge',
    spanName: 'payment.charge',
    kind: SpanKind::KIND_CLIENT,
    attributes: ['payment.provider' => 'stripe'],
    attributeCallback: fn($instance, $params, $class, $function) => [
        'payment.amount' => $params[0] ?? null,
    ],
);
```

### Options

[](#options)

OptionTypeDefaultDescription`class``string`(required)Fully qualified class name`method``string`(required)Method name to hook`spanName``string|null``FQCN::method`Custom span name`kind``int``KIND_INTERNAL`SpanKind constant`attributes``array``[]`Static span attributes`attributeCallback``Closure|null``null``fn($instance, $params, $class, $function): array` — use `register()` instead of Configure for this optionEnvironment Variables
---------------------

[](#environment-variables)

```
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-cakephp-app
OTEL_TRACES_EXPORTER=otlp
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
```

OtelErrorLoggingMiddleware
--------------------------

[](#otelerrorloggingmiddleware)

A PSR-15 middleware that catches 500-level exceptions and emits them as OpenTelemetry log records. The log is automatically associated with the current span, so you can view related errors directly in your trace backend (Jaeger, Grafana Tempo, etc.).

- `HttpException` with status code &gt;= 500: logged
- `HttpException` with status code &lt; 500 (e.g. 404): not logged
- Non-`HttpException` (unexpected errors): logged as 500

### Setup

[](#setup)

Add it **after** `ErrorHandlerMiddleware` in your `Application::middleware()`:

```
use OtelInstrumentation\Middleware\OtelErrorLoggingMiddleware;

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue
        ->add(new ErrorHandlerMiddleware())
        ->add(new OtelErrorLoggingMiddleware())
        // ...
    ;
}
```

TraceAwareLogger
----------------

[](#traceawarelogger)

A PSR-3 LoggerInterface decorator that automatically injects `trace_id` / `span_id` into log `context`.

```
$logger = new \OtelInstrumentation\Log\TraceAwareLogger($existingPsr3Logger);
```

License
-------

[](#license)

MIT

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance93

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 93.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~18 days

Total

4

Last Release

38d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/63869?v=4)[Kaz Watanabe](/maintainers/kaz29)[@kaz29](https://github.com/kaz29)

---

Top Contributors

[![kaz29](https://avatars.githubusercontent.com/u/63869?v=4)](https://github.com/kaz29 "kaz29 (27 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/kaz29-cakephp-otel-plugin/health.svg)

```
[![Health](https://phpackages.com/badges/kaz29-cakephp-otel-plugin/health.svg)](https://phpackages.com/packages/kaz29-cakephp-otel-plugin)
```

###  Alternatives

[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

562565.8k42](/packages/ecotone-ecotone)[keepsuit/laravel-opentelemetry

OpenTelemetry integration for laravel

162476.0k](/packages/keepsuit-laravel-opentelemetry)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

749284.3k37](/packages/civicrm-civicrm-core)[drupal/core-dev

require-dev dependencies from drupal/drupal; use in addition to drupal/core-recommended to run tests from drupal/core.

2022.0M321](/packages/drupal-core-dev)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
