axy/backtrace
axy/backtrace is a lightweight PHP 8.1+ helper for working with call stacks. It provides Trace and ExceptionTrace utilities to inspect and trim backtraces, useful for debugging and cleaning up exception stack displays in apps and libraries.
Installation:
composer require axy/backtrace
Requires PHP 8.0+ and Laravel 8+ (or standalone PHP).
Basic Usage:
use Axy\Backtrace\Backtrace;
$backtrace = new Backtrace();
$backtrace->start('user_action'); // Start a trace with a label
// Simulate some operations
$backtrace->step('database_query', ['query' => 'SELECT * FROM users']);
$backtrace->step('process_data', ['count' => 10]);
$backtrace->end(); // End the trace
$traceData = $backtrace->getTrace(); // Get structured trace data
First Use Case:
Backtrace to log execution steps with timestamps and metadata.public function index()
{
$backtrace = new Backtrace();
$backtrace->start('UserController@index');
$users = User::query()->get();
$backtrace->step('User::all', ['count' => $users->count()]);
return response()->json($users);
}
Where to Look First:
src/Backtrace.php for API reference.tests/ for advanced use cases (e.g., nested traces, custom steps).Structured Tracing:
start()/end() to demarcate logical blocks (e.g., API routes, jobs, commands).$backtrace->start('process_order');
$backtrace->start('validate_payment');
// ... validation logic
$backtrace->end(); // End nested trace
$backtrace->end(); // End parent trace
Integration with Laravel:
Backtrace into middleware to trace HTTP requests:
public function handle(Request $request, Closure $next)
{
$backtrace = new Backtrace();
$backtrace->start('HTTP_REQUEST', ['method' => $request->method()]);
$response = $next($request);
$backtrace->step('HTTP_RESPONSE', ['status' => $response->status()]);
$backtrace->end();
return $response;
}
Backtrace to the container for dependency injection:
$this->app->singleton(Backtrace::class, fn() => new Backtrace());
Custom Step Metadata:
$backtrace->step('authenticate_user', [
'user_id' => auth()->id(),
'provider' => 'sanctum',
]);
Async Operations:
Backtrace in queues/jobs to trace background tasks:
public function handle()
{
$backtrace = new Backtrace();
$backtrace->start('SendEmailJob');
Mail::to($this->user->email)->send(new WelcomeEmail());
$backtrace->step('Mail::send', ['recipient' => $this->user->email]);
$backtrace->end();
}
Output Formats:
Log::info('Trace', ['data' => $backtrace->getTrace()]);
Backtrace::toArray() or toJson() for serialization.Memory Leaks:
Backtrace instances in long-lived objects (e.g., app state). Traces accumulate steps and can bloat memory.$backtrace->reset().Nested Trace Mismatches:
end() for nested traces will corrupt the hierarchy.try-finally block or a context manager:
$backtrace->start('outer');
try {
$backtrace->start('inner');
// ...
} finally {
$backtrace->end();
}
$backtrace->end();
Performance Overhead:
if (config('app.debug')) {
$backtrace->step('loop_iteration', ['index' => $i]);
}
Thread Safety:
Backtrace is not thread-safe. Avoid sharing instances across concurrent requests (e.g., in Laravel’s app singleton).AppServiceProvider::boot() or use per-request instances.Timestamp Precision:
microtime(true), which may not align with system clocks in distributed environments.Inspect Traces:
dd($backtrace->getTrace()) to visualize the trace structure during development.end() calls or misaligned hierarchies.Log Exceptions:
try {
$backtrace->start('risky_operation');
// ...
} catch (\Exception $e) {
Log::error('Failed', [
'trace' => $backtrace->getTrace(),
'error' => $e->getMessage(),
]);
throw $e;
} finally {
$backtrace->end();
}
Custom Step Validation:
Backtrace::step() to validate metadata:
$backtrace->step('custom_step', ['required_field' => 'value']);
Custom Step Types:
Backtrace to add domain-specific steps:
class DomainBacktrace extends Backtrace
{
public function databaseQuery(string $query, array $bindings = [])
{
$this->step('db.query', compact('query', 'bindings'));
}
}
Output Adapters:
Axy\Backtrace\Contracts\TraceOutput to write traces to custom destinations (e.g., OpenTelemetry, Datadog):
class OpenTelemetryAdapter implements TraceOutput
{
public function write(array $trace): void
{
// Convert to OpenTelemetry spans
}
}
Middleware Integration:
Backtrace:
class TraceMiddleware
{
public function handle($request, Closure $next)
{
$backtrace = new Backtrace();
$backtrace->start('HTTP', ['uri' => $request->fullUrl()]);
try {
return $next($request);
} finally {
$backtrace->end();
Log::debug('Trace', ['data' => $backtrace->getTrace()]);
}
}
}
Performance Profiling:
laravel-debugbar to visualize traces in the browser:
Debugbar::info('Trace', $backtrace->getTrace());
How can I help you explore Laravel packages today?