flow-php/telemetry
Flow Telemetry is a PHP library for metrics and tracing, built to integrate smoothly with Flow PHP ETL pipelines. Use it to instrument jobs, collect runtime metrics, and add traces for observability. Includes docs, installation, and upgrade guides.
Installation:
composer require flow-php/telemetry
Ensure compatibility with Laravel 10/11 (PHP 8.3+).
Basic Initialization:
Since there’s no Laravel service provider, manually bind the Telemetry class in AppServiceProvider:
use Flow\Telemetry\Telemetry;
public function register()
{
$this->app->singleton(Telemetry::class, fn() => new Telemetry());
}
First Use Case: Metrics Collection Track a simple counter (e.g., API requests):
use Flow\Telemetry\Metrics\Counter;
$counter = app(Telemetry::class)->counter('api.requests');
$counter->increment();
First Use Case: Tracing Instrument a route or job with a span:
use Flow\Telemetry\Tracing\Span;
use Flow\Telemetry\Tracing\Tracer;
$tracer = app(Telemetry::class)->tracer();
$span = $tracer->startSpan('process.order');
try {
// Business logic
} finally {
$span->end();
}
Configuration:
Define exporters (e.g., Prometheus) in a custom config file (config/telemetry.php):
return [
'exporters' => [
'prometheus' => [
'host' => 'localhost',
'port' => 9090,
],
],
];
Load it via config() helper or service provider.
Metrics Collection:
jobs.processed).
$counter = app(Telemetry::class)->counter('jobs.processed');
$counter->increment(5); // Batch increment
queue.size).
$gauge = app(Telemetry::class)->gauge('queue.size');
$gauge->set(100);
api.response.time).
$histogram = app(Telemetry::class)->histogram('api.response.time');
$histogram->record(150); // Milliseconds
Tracing:
$span = $tracer->startSpan('fetch.user', ['user_id' => 123]);
$span->addEvent('query', ['sql' => 'SELECT * FROM users']);
$span->end();
$context = $span->getContext();
$client->withContext($context)->request(...);
Integration with Laravel:
public function handle(Request $request, Closure $next)
{
$span = app(Tracer::class)->startSpan('http.request');
try {
return $next($request);
} finally {
$span->end();
}
}
public function handle()
{
$span = app(Tracer::class)->startSpan('process.invoice');
// Job logic
$span->end();
}
Event::listen(JobProcessed::class, function () {
app(Telemetry::class)->counter('jobs.processed')->increment();
});
Exporters:
config/telemetry.php:
'exporters' => [
'prometheus' => [
'host' => env('TELEMETRY_HOST', 'localhost'),
'port' => env('TELEMETRY_PORT', 9090),
],
'logging' => [
'channel' => 'telemetry',
],
],
Telemetry facade or service container to flush data:
app(Telemetry::class)->flush();
Avoid Tight Coupling:
Telemetry in a Laravel-compatible interface (e.g., TelemetryService) to abstract Flow-specific details.class TelemetryService
{
public function counter(string $name): CounterInterface
{
return app(Telemetry::class)->counter($name);
}
}
Leverage Laravel Facades:
Telemetry facade for cleaner syntax:
// app/Facades/Telemetry.php
public static function counter(string $name): CounterInterface
{
return app(TelemetryService::class)->counter($name);
}
Usage:
Telemetry::counter('api.calls')->increment();
Batch Metrics:
use Illuminate\Support\Facades\Schedule;
Schedule::call(function () {
app(Telemetry::class)->flush();
})->everyFiveSeconds();
Context Propagation:
$client = new Client([
'handler' => HandlerStack::create([
new SpanPropagationMiddleware($tracer),
]),
]);
Custom Exporters:
TelemetryExporter interface to support non-Prometheus backends (e.g., Datadog, InfluxDB):
class DatadogExporter implements ExporterInterface
{
public function export(MetricData $data): void
{
// Send to Datadog API
}
}
No Laravel Conventions:
Telemetry in AppServiceProvider.config/telemetry.php by default. Requires custom setup.Telemetry facade).Flow PHP Dependency:
Tracing Overhead:
Limited Documentation:
Metric Naming:
laravel.api.) to avoid conflicts with Flow’s metrics.Metrics Not Appearing:
app(Telemetry::class)->flush() manually to debug.'exporters' => [
'logging' => [
'channel' => 'telemetry',
'level' => 'debug',
],
],
Tracing Issues:
end().$tracer->withSampler(new AlwaysSample());
Performance Bottlenecks:
user_id in counters).app(Telemetry::class)->setFlushInterval(10); // Seconds
Start Small:
Use Laravel’s Observability:
if (app()->environment('production')) {
Telemetry::counter('api.requests')->increment();
}
Custom Metric Names:
How can I help you explore Laravel packages today?