inspector-apm/inspector-php
Inspector APM PHP agent: instrument your Laravel/PHP apps to collect traces, transactions, errors, and performance metrics. Lightweight integration, configurable sampling and context, helps you find slow requests and production issues fast.
Installation:
composer require inspector-apm/inspector-php
Add your INSPECTOR_API_KEY to .env:
INSPECTOR_API_KEY=your_ingestion_key_here
Basic Setup in Laravel:
Add to bootstrap/app.php (or AppServiceProvider):
use Inspector\Inspector;
use Inspector\Configuration;
$configuration = new Configuration(env('INSPECTOR_API_KEY'));
$inspector = new Inspector($configuration);
app()->singleton('inspector', fn() => $inspector);
First Use Case:
Instrument a route in app/Http/Controllers/ExampleController.php:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
public function index(Request $request) {
$inspector = App::make('inspector');
$inspector->startTransaction($request->path());
$result = $inspector->addSegment(function($segment) {
// Your business logic here
return "Processed";
}, 'process-data');
return response()->json(['result' => $result]);
}
Verify: Check the Inspector Dashboard for traces.
// app/Http/Middleware/InspectorMiddleware.php
public function handle(Request $request, Closure $next) {
$inspector = app('inspector');
$inspector->startTransaction($request->path());
return $next($request);
}
Register in app/Http/Kernel.php:
protected $middleware = [
\App\Http\Middleware\InspectorMiddleware::class,
];
public function processOrder(Order $order) {
$inspector = app('inspector');
return $inspector->addSegment(function() use ($order) {
// Order processing logic
return $order->process();
}, 'order-processing');
}
public function scopeWithInspector($query) {
$inspector = app('inspector');
return $inspector->addSegment(function() use ($query) {
return $query->get();
}, 'eloquent-query');
}
public function handle() {
$inspector = app('inspector');
$inspector->startTransaction('job:process-payment');
// Job logic
}
$inspector->addSegment(function() {
return DB::select('SELECT * FROM complex_query');
}, 'complex-query');
$inspector->registerGlobalHandler();
try {
$result = $inspector->addSegment(...);
} catch (\Exception $e) {
$inspector->addSegment(function() use ($e) {
throw $e; // Captures exception in trace
}, 'failing-operation');
}
Service Container Binding: Bind the inspector instance globally for easy access:
$app->bind('inspector', function() {
return new Inspector(new Configuration(env('INSPECTOR_API_KEY')));
});
View Rendering: Track template rendering time:
$inspector->addSegment(function() use ($view) {
return $view->render();
}, 'view-render');
API Resources: Instrument serialization:
$inspector->addSegment(function() use ($resource) {
return $resource->toArray();
}, 'resource-serialization');
$configuration->setSamplingRate(0.1); // 10% of requests
$configuration->setExcludedPaths(['/health', '/ping']);
Context Propagation: Pass context (e.g., user ID) across segments:
$inspector->addSegment(function($segment) {
$segment->setAttribute('user_id', auth()->id());
// Logic
}, 'user-specific-operation');
Custom Metrics: Track business metrics:
$inspector->addMetric('orders_processed', 1, ['status' => 'success']);
Double Instrumentation:
user-service:fetch-profile).Segment Nesting Errors:
addSegment with closures to ensure proper scope:
$result = $inspector->addSegment(function($segment) {
$child = $segment->startChild('child-operation');
$child->end();
return "Done";
}, 'parent-operation');
Async Task Corruption:
fork() for concurrent tasks:
$scope = $inspector->fork();
$scope->startSegment('async-task')->end();
Global Handler Conflicts:
registerGlobalHandler() overriding existing exception handlers.try {
$inspector->registerGlobalHandler();
} catch (\Exception $e) {
// Handle conflict
}
High Cardinality Attributes:
$segment->setAttribute('user_type', auth()->user()->type);
Missing Traces:
INSPECTOR_API_KEY is correct and the agent is running (if using agent mode).$configuration->setDebug(true);
Performance Overhead:
Segment Not Showing:
addSegment with closures).finally block to guarantee closure:
$inspector->addSegment(function() {
// Logic
}, 'segment-name', function() {
// Always runs
});
Transport Layer:
$inspector->setTransport(function() {
return new CustomTransportWithRetry();
});
Environment Variables:
$configuration = new Configuration(
env('INSPECTOR_API_KEY', 'local-dev-key')
);
Sampling:
$configuration->setSamplingCallback(function($transaction) {
return $transaction->getName() === '/api/payments' ? 1.0 : 0.1;
});
Custom Models:
\Inspector\Models\Model to add domain-specific attributes:
class CustomModel extends \Inspector\Models\Model {
public function setCustomAttribute($key, $value) {
$this->attributes[$key] = $value;
}
}
$configuration->setModelClass(CustomModel::class);
Hooks:
$inspector->onTransactionStart(function($transaction) {
$transaction->setAttribute('environment', app()->environment());
});
Plugin System:
public function register() {
$ins
How can I help you explore Laravel packages today?