PHPackages                             cascata/hyperf-opentelemetry - 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. [Logging &amp; Monitoring](/categories/logging)
4. /
5. cascata/hyperf-opentelemetry

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

cascata/hyperf-opentelemetry
============================

Drop-in OpenTelemetry integration for Hyperf 3.1+ (traces, metrics and logs via OTLP).

v0.1.0(3w ago)02MITPHPPHP &gt;=8.1

Since May 14Pushed 3w agoCompare

[ Source](https://github.com/Jo1oPedro/hyperf-observability-package)[ Packagist](https://packagist.org/packages/cascata/hyperf-opentelemetry)[ RSS](/packages/cascata-hyperf-opentelemetry/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (17)Versions (2)Used By (0)

cascata/hyperf-opentelemetry
============================

[](#cascatahyperf-opentelemetry)

Drop-in OpenTelemetry integration for **Hyperf 3.1+** — traces, metrics and logs via OTLP, with sensible Swoole defaults.

Out of the box you get:

- HTTP server spans for every inbound request (`SERVER` kind, W3C TraceContext propagation)
- `#[Traced]` attribute to wrap any service/use-case/repository method in a span
- Correlation ID middleware (propagates `X-Correlation-Id`)
- Monolog handler that ships every log via OTLP, with `trace_id`/`span_id` injected automatically
- Coroutine-safe trace context (survives the end of individual spans, so logs emitted by exception handlers still correlate)
- Optional Docker Compose stack with OTel Collector → Tempo / Prometheus / Loki / Grafana

---

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

[](#requirements)

PHP`>= 8.1`Hyperf`~3.1.0`Swoole`>= 5.0`ext-grpc**not required** (uses OTLP HTTP)---

Install
-------

[](#install)

```
composer require cascata/hyperf-opentelemetry
```

Register the tracing middleware in `config/autoload/middlewares.php`:

```
return [
    'http' => [
        \Cascata\HyperfOpenTelemetry\Middleware\CorrelationIdMiddleware::class,
        \Cascata\HyperfOpenTelemetry\Middleware\TracingMiddleware::class,
        // ... your other middlewares
    ],
];
```

Add the Monolog handler to `config/autoload/logger.php` (your existing config):

```
use Cascata\HyperfOpenTelemetry\Logging\OtelLogHandler;
use Cascata\HyperfOpenTelemetry\Logging\OtelTraceContextProcessor;
use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;

return [
    'default' => [
        'handlers' => [
            [
                'class' => StreamHandler::class,
                'constructor' => [
                    'stream' => BASE_PATH . '/runtime/logs/hyperf.log',
                    'level'  => Logger::DEBUG,
                ],
                'formatter' => [
                    'class' => JsonFormatter::class,
                    'constructor' => [],
                ],
            ],
            [
                'class' => OtelLogHandler::class,
                'constructor' => [
                    'level' => Logger::INFO,
                ],
            ],
        ],
        'processors' => [
            ['class' => OtelTraceContextProcessor::class],
        ],
    ],
];
```

Set environment variables:

```
OTEL_ENABLED=true
OTEL_SERVICE_NAME=my-service
OTEL_SERVICE_NAMESPACE=mycompany
OTEL_SERVICE_VERSION=1.0.0
OTEL_DEPLOYMENT_ENV=dev
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_TRACES_SAMPLER_ARG=1.0
```

Clear the DI proxy cache and you're done:

```
rm -rf runtime/container
```

---

Usage
-----

[](#usage)

### Annotate methods you want traced

[](#annotate-methods-you-want-traced)

```
use Cascata\HyperfOpenTelemetry\Tracing\Annotation\Traced;

class CreateUser
{
    #[Traced(name: 'usecase.user.create')]
    public function execute(CreateUserInput $input): CreateUserOutput
    {
        // automatic span: usecase.user.create
    }
}
```

Span kinds:

```
#[Traced(name: 'mq.welcome.publish', kind: 'producer')]    // PRODUCER (publish)
#[Traced(name: 'mq.welcome.consume', kind: 'consumer')]    // CONSUMER (read)
#[Traced(name: 'http.payment.charge', kind: 'client')]     // CLIENT (outbound)
#[Traced(name: 'usecase.foo')]                             // INTERNAL (default)
```

### Aspects only work on methods that:

[](#aspects-only-work-on-methods-that)

- are **public, non-static**
- belong to classes resolved by the Hyperf container (DI)

Methods called via `new ClassName()` won't be intercepted.

### Custom metrics

[](#custom-metrics)

```
use OpenTelemetry\API\Globals;

$meter   = Globals::meterProvider()->getMeter('my-service.business');
$counter = $meter->createCounter('orders_created_total');
$counter->add(1, ['tenant' => $tenantId]);
```

---

Publish optional resources
--------------------------

[](#publish-optional-resources)

The package ships an optional config file and a complete Docker Compose stack.

```
# Publish opentelemetry.php to config/autoload/
php bin/hyperf.php vendor:publish cascata/hyperf-opentelemetry --id=config

# Publish Tempo + Prometheus + Loki + Grafana + OTel Collector docker stack
php bin/hyperf.php vendor:publish cascata/hyperf-opentelemetry --id=observability-stack
```

The published stack lives at `BASE_PATH/observability/`. Bring it up with:

```
docker network create hyperf-network    # only once
cd observability && docker compose up -d
```

Grafana: `http://localhost:3000` (anonymous Admin).

---

Architecture
------------

[](#architecture)

```
Application code
      │  $logger->info()    or   handler emits span
      ▼
Cascata\HyperfOpenTelemetry        ──► global TracerProvider / MeterProvider / LoggerProvider
      │
      ▼
OTLP HTTP (4318)
      │
      ▼
OTel Collector  ──►  Tempo   (traces)
                ──►  Prom    (metrics, via spanmetrics connector)
                ──►  Loki    (logs)
                          │
                          ▼
                       Grafana

```

The application only ever speaks OTLP to the collector. Swapping Tempo for Jaeger, or Loki for Elasticsearch, only changes the collector config — your code does not change.

---

Configuration reference
-----------------------

[](#configuration-reference)

All values can be set via env or by publishing `opentelemetry.php`.

Env varDefaultPurpose`OTEL_ENABLED``true`Master switch`OTEL_SERVICE_NAME``hyperf-app``service.name` resource attribute`OTEL_SERVICE_NAMESPACE``default``service.namespace``OTEL_SERVICE_VERSION``1.0.0``service.version``OTEL_DEPLOYMENT_ENV``dev``deployment.environment.name``OTEL_EXPORTER_OTLP_ENDPOINT``http://otel-collector:4318`OTLP HTTP base URL`OTEL_TRACES_SAMPLER_ARG``1.0`TraceID-ratio sampler (0.0 – 1.0)---

Troubleshooting
---------------

[](#troubleshooting)

**No spans / logs / metrics arriving in Grafana**

Verify the collector is reachable from inside the app container:

```
docker exec  curl -s -o /dev/null -w "%{http_code}\n" \
  http://otel-collector:4318/v1/traces -X POST \
  -H "Content-Type: application/x-protobuf" --data "test"
# expected: 400 (means the endpoint is up, payload was rejected as expected)
```

Enable internal debug logging:

```
OTEL_LOG_LEVEL=debug
OTEL_PHP_INTERNAL_LOG_LEVEL=debug
```

**`Span::getCurrent()` returns no-op span in exception handlers**

That's why this package also stores `trace_id`/`span_id` in `Hyperf\Context` — logs emitted after a span closes still correlate. No action needed on your side.

**Changes to `#[Traced]` annotations don't take effect**

The Hyperf DI proxy cache must be regenerated:

```
rm -rf runtime/container && php bin/hyperf.php start
```

**Batch processor doesn't flush in Swoole**

This package uses `SimpleSpanProcessor` / `SimpleLogRecordProcessor` by default — they export synchronously, which is the safe choice in long-running Swoole workers. For very high-throughput services, consider implementing a periodic flush listener instead.

---

Versioning
----------

[](#versioning)

BranchHyperfOTel SDK`1.x``~3.1.0``^1.1`Follows [SemVer](https://semver.org/).

---

License
-------

[](#license)

MIT

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance94

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity32

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% 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

Unknown

Total

1

Last Release

27d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3c1933f51a5554c9a257104dfe57612d727189428f1ffcd68b3be6fe6f201f62?d=identicon)[João Pedro](/maintainers/Jo%C3%A3o%20Pedro)

---

Top Contributors

[![Jo1oPedro](https://avatars.githubusercontent.com/u/84350827?v=4)](https://github.com/Jo1oPedro "Jo1oPedro (1 commits)")

---

Tags

logsMetricstracingopentelemetryotelotlpswooleobservabilityhyperfprometheusgrafanalokitempo

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/cascata-hyperf-opentelemetry/health.svg)

```
[![Health](https://phpackages.com/badges/cascata-hyperf-opentelemetry/health.svg)](https://phpackages.com/packages/cascata-hyperf-opentelemetry)
```

###  Alternatives

[friendsofopentelemetry/opentelemetry-bundle

Traces, metrics, and logs instrumentation within your Symfony application

6510.2k](/packages/friendsofopentelemetry-opentelemetry-bundle)[open-telemetry/sdk

SDK for OpenTelemetry PHP.

2326.5M315](/packages/open-telemetry-sdk)[keepsuit/laravel-opentelemetry

OpenTelemetry integration for laravel

162476.0k](/packages/keepsuit-laravel-opentelemetry)[open-telemetry/opentelemetry-auto-laravel

OpenTelemetry auto-instrumentation for Laravel

582.4M8](/packages/open-telemetry-opentelemetry-auto-laravel)[open-telemetry/opentelemetry-auto-symfony

OpenTelemetry auto-instrumentation for Symfony

561.5M3](/packages/open-telemetry-opentelemetry-auto-symfony)[traceway/opentelemetry-symfony

Pure-PHP OpenTelemetry instrumentation for Symfony — automatic HTTP, Console, HttpClient, Messenger, Doctrine DBAL, Cache, Twig tracing and Monolog log-trace correlation with response propagation, a lightweight Tracing helper, route templates, and semantic conventions. No C extension required (ext-protobuf recommended for production).

724.6k](/packages/traceway-opentelemetry-symfony)

PHPackages © 2026

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