tracekit / laravel-apm
TraceKit APM for Laravel - Zero-config distributed tracing and code monitoring
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.0
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- open-telemetry/api: ^1.0
- open-telemetry/exporter-otlp: ^1.0
- open-telemetry/sdk: ^1.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0
README
Zero-config distributed tracing and performance monitoring for Laravel applications.
Features
- Zero Configuration - Works out of the box with sensible defaults
- Automatic Instrumentation - No code changes needed
- HTTP Request Tracing - Track every request, route, and middleware
- Database Query Monitoring - See every query with actual SQL and bindings
- Queue Job Tracking - Monitor Laravel jobs and queues
- Slow Query Detection - Automatically highlight slow database queries
- Error Tracking - Capture exceptions with full context
- Code Monitoring - Live debugging with breakpoints and variable inspection
- Metrics API - Counter, Gauge, and Histogram metrics with automatic OTLP export
- Low Overhead - < 5% performance impact
Installation
composer require tracekit/laravel-apm
Quick Start
1. Install the package
php artisan tracekit:install
2. Add your API key to .env
TRACEKIT_API_KEY=your-api-key-here TRACEKIT_SERVICE_NAME=my-laravel-app # Optional: Custom endpoint (defaults to https://app.tracekit.dev/v1/traces) # TRACEKIT_ENDPOINT=https://your-custom-endpoint.com/v1/traces
Get your API key at https://app.tracekit.dev
3. Done!
Your Laravel app is now automatically traced. Visit your TraceKit dashboard to see your traces.
Local Development
Debug your Laravel application locally without creating a cloud account using TraceKit Local UI.
Quick Start
# Install Local UI globally npm install -g @tracekit/local-ui # Start it tracekit-local
The Local UI will start at http://localhost:9999 and automatically open in your browser.
How It Works
When running in local or development environment (Laravel's APP_ENV), the SDK automatically:
- Detects if Local UI is running at
http://localhost:9999 - Sends traces to both Local UI and cloud (if API key is present)
- Falls back gracefully if Local UI is not available
No code changes needed! Just set your .env:
APP_ENV=local TRACEKIT_API_KEY=your-key # Optional - works without it!
Then run your app:
php artisan serve
You'll see traces appear in real-time at http://localhost:9999.
Features
- Real-time trace viewing in your browser
- Works completely offline
- No cloud account required
- Zero configuration
- Automatic cleanup (1000 traces max, 1 hour retention)
Local-Only Development
To use Local UI without cloud sending:
APP_ENV=local # Don't set TRACEKIT_API_KEY
Traces will only go to Local UI.
Disabling Local UI
To disable automatic Local UI detection:
APP_ENV=production # or don't run Local UI
Learn More
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=tracekit-config
This creates config/tracekit.php where you can customize:
Laravel 12 Setup
Laravel 12 changed how middleware is registered. TraceKit attempts to register middleware automatically for all Laravel versions (10, 11, and 12).
If automatic registration doesn't work, you can manually add the TraceKit middleware to your bootstrap/app.php:
use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Middleware; use TraceKit\Laravel\Middleware\TracekitMiddleware; return Application::configure(basePath: dirname(__DIR__)) ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ TracekitMiddleware::class, ]); $middleware->api(append: [ TracekitMiddleware::class, ]); }) // ... rest of your configuration ->create();
For most cases, the automatic registration via the service provider should work without any manual configuration.
Configuration Options
return [ // Enable/disable tracing 'enabled' => env('TRACEKIT_ENABLED', env('APP_ENV') !== 'local'), // Your TraceKit API key 'api_key' => env('TRACEKIT_API_KEY', ''), // OTLP endpoint for sending traces 'endpoint' => env('TRACEKIT_ENDPOINT', 'https://app.tracekit.dev/v1/traces'), // Service name as it appears in TraceKit 'service_name' => env('TRACEKIT_SERVICE_NAME', env('APP_NAME', 'laravel-app')), // Sample rate (0.0 to 1.0) 'sample_rate' => env('TRACEKIT_SAMPLE_RATE', 1.0), // Enable/disable specific features 'features' => [ 'http' => env('TRACEKIT_HTTP_ENABLED', true), 'database' => env('TRACEKIT_DATABASE_ENABLED', true), 'cache' => env('TRACEKIT_CACHE_ENABLED', true), // Coming soon 'queue' => env('TRACEKIT_QUEUE_ENABLED', true), 'redis' => env('TRACEKIT_REDIS_ENABLED', true), // Coming soon ], // Routes to ignore 'ignored_routes' => [ '/health', '/up', '/_healthz', ], // Slow query threshold (ms) 'slow_query_threshold' => env('TRACEKIT_SLOW_QUERY_MS', 100), // Include query bindings in traces 'include_query_bindings' => env('TRACEKIT_INCLUDE_BINDINGS', true), // Map hostnames to service names for service graph 'service_name_mappings' => [ 'localhost:8082' => 'payment-service', 'localhost:8083' => 'user-service', ], ];
Code Monitoring (Live Debugging)
TraceKit includes production-safe code monitoring for live debugging without redeployment.
Enable Code Monitoring
Add to your .env file:
TRACEKIT_CODE_MONITORING_ENABLED=true TRACEKIT_CODE_MONITORING_POLL_INTERVAL=30 # How often to check for breakpoints (seconds) # Supported: 1, 5, 10, 15, 30, 60, 300, 600 # Lower = faster updates, higher load TRACEKIT_CODE_MONITORING_MAX_DEPTH=3 # Nested array/object inspection depth TRACEKIT_CODE_MONITORING_MAX_STRING=1000 # Max length for captured strings
Configuration Options:
enabled: Master switch for code monitoring (default:false)poll_interval: Background polling frequency in seconds (default:30)1= Every second (highest load, instant updates)5= Every 5 seconds (high load, very fast updates)10= Every 10 seconds (moderate load, fast updates)30= Every 30 seconds (recommended for production)60= Every minute (low load, slower updates)300+= Every 5+ minutes (very low load, periodic checks)
max_variable_depth: How deep to inspect nested structures (default:3)max_string_length: Maximum string length to capture (default:1000)
Add Debug Points
Add checkpoints anywhere in your code to capture variable state and stack traces:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class CheckoutController extends Controller { public function processPayment(Request $request) { $cart = $request->input('cart'); $userId = $request->input('user_id'); // Automatic snapshot capture with label tracekit_snapshot('checkout-validation', [ 'user_id' => $userId, 'cart_items' => count($cart['items'] ?? []), 'total_amount' => $cart['total'] ?? 0, ]); try { // Process payment $result = $this->paymentService->charge($cart['total'], $userId); // Another checkpoint tracekit_snapshot('payment-success', [ 'user_id' => $userId, 'payment_id' => $result['payment_id'], 'amount' => $result['amount'], ]); return response()->json(['success' => true]); } catch (\Exception $e) { // Automatic error capture (configured in service provider) tracekit_error_snapshot($e, [ 'user_id' => $userId, 'cart_total' => $cart['total'] ?? 0, ]); return response()->json(['error' => 'Payment failed'], 500); } } }
Helper Functions
TraceKit provides convenient helper functions:
// Basic snapshot capture tracekit_snapshot('my-label', ['key' => 'value']); // Debug helper (logs + captures) tracekit_debug('debug-point', ['data' => $data]); // Error snapshot with exception details tracekit_error_snapshot($exception, ['context' => 'additional data']);
Automatic Breakpoint Management
- Auto-Registration: First call to
tracekit_snapshot()automatically creates breakpoints in TraceKit - Smart Matching: Breakpoints match by function name + label (stable across code changes)
- Background Sync: SDK polls for active breakpoints every 30 seconds
- Production Safe: No performance impact when breakpoints are inactive
What Gets Captured
Snapshots include:
- Variables: Local variables at capture point
- Stack Trace: Full call stack with file/line numbers
- Request Context: HTTP method, URL, headers, query params
- Execution Time: When the snapshot was captured
- Eloquent Models: Automatically serialized with relationships
Exception Handling
Exceptions are automatically captured when TRACEKIT_CODE_MONITORING_ENABLED=true - no additional code required!
The TraceKit service provider automatically registers an exception reporter that:
- Captures full stack traces with file and line numbers
- Records exception type, message, and context
- Includes HTTP request details (route, headers, params)
- Enables automatic code discovery for debugging
// Exceptions are automatically captured - just throw them as normal! Route::post('/payment', function (Request $request) { if (!$request->has('amount')) { // This exception will be automatically captured with full context throw new \Exception('Amount is required'); } $payment = Payment::process($request->amount); return response()->json(['payment_id' => $payment->id]); }); // You can also manually add snapshots before throwing Route::post('/checkout', function (Request $request) { try { $order = Order::create($request->all()); } catch (\Exception $e) { // Optional: Add additional context before exception is auto-captured tracekit_snapshot('checkout-failed', [ 'cart_total' => $request->input('total'), 'user_id' => auth()->id(), 'error' => $e->getMessage(), ]); throw $e; // Still automatically captured! } });
How It Works:
- Any uncaught exception is automatically reported to TraceKit
- Stack trace is formatted and attached to the current OpenTelemetry span
- Exception event includes
exception.stacktracefor code discovery - TraceKit backend parses stack traces and indexes your code locations
- Visit the "Browse Code" tab in
/snapshotsto see discovered code
PII Scrubbing
TraceKit Laravel SDK automatically scans snapshot variables for sensitive data before sending to the server. This ensures that passwords, API keys, and other credentials never leave your application.
How It Works
Sensitive data is detected in two ways:
- By variable name — Variables with sensitive names are redacted as
[REDACTED:sensitive_name] - By value pattern — Values matching known sensitive patterns are redacted as
[REDACTED:type]
Auto-Detected Sensitive Names
The SDK flags variables whose names contain any of the following (case-insensitive):
password, passwd, pwd, secret, token, key, credential, api_key, apikey
Name matching uses letter-based boundaries (not \b) so compound names like api_key, user_token, and db_password are correctly detected.
Auto-Detected Value Patterns
| Pattern | Example | Redacted As |
|---|---|---|
| Credit card numbers | 4111111111111111 |
[REDACTED:credit_card] |
| Email addresses | user@example.com |
[REDACTED:email] |
| Social Security Numbers | 123-45-6789 |
[REDACTED:ssn] |
| JWT tokens | eyJhbGciOiJIUzI1NiIs... |
[REDACTED:jwt] |
| AWS access keys | AKIAIOSFODNN7EXAMPLE |
[REDACTED:aws_key] |
| Stripe keys | sk_live_abc123... |
[REDACTED:stripe_key] |
| Private keys | -----BEGIN RSA PRIVATE KEY----- |
[REDACTED:private_key] |
Example
tracekit_snapshot('user-login', [ 'username' => 'jdoe', // Sent as-is 'password' => 'secret123', // -> [REDACTED:sensitive_name] 'api_key' => 'sk_live_abc...', // -> [REDACTED:sensitive_name] 'email' => 'user@example.com', // -> [REDACTED:email] 'card' => '4111111111111111', // -> [REDACTED:credit_card] ]);
PII scrubbing is enabled by default and requires no configuration.
Kill Switch
TraceKit provides a server-side toggle to disable code monitoring per service without deploying code changes.
How It Works
When the kill switch is enabled for your service on the TraceKit dashboard (or via API), all snapshot captures are suppressed. No breakpoint data is sent.
Important: Laravel uses a per-request architecture (process-per-request), so kill switch state cannot be held in memory across requests. Instead, the SDK checks kill switch state via Laravel Cache on each request.
// No code changes needed — the SDK handles this automatically. // Kill switch state is cached and refreshed on each poll cycle. // To check kill switch state manually: $client = app(\TraceKit\Laravel\SnapshotClient::class); // The client checks cache for kill switch state before every capture
Controlling the Kill Switch
- Dashboard: Toggle code monitoring on/off per service in the TraceKit dashboard
- API:
POST /api/services/:name/kill-switchwith{"enabled": true}or{"enabled": false}
When disabled, code monitoring resumes automatically on the next poll cycle.
SSE Real-time Updates
Not applicable for Laravel's request lifecycle. Laravel processes each request in a separate PHP process, so persistent SSE connections are not feasible.
Instead, breakpoint updates are received via polling (default 30-second interval) and cached using Laravel's cache driver. This ensures breakpoint state is shared across all request processes.
Configure the poll interval in your .env:
TRACEKIT_CODE_MONITORING_POLL_INTERVAL=30
Circuit Breaker
The circuit breaker protects your application if the TraceKit backend becomes unreachable.
How It Works
- The SDK tracks consecutive snapshot capture failures
- After 3 failures within 60 seconds, code monitoring is automatically paused
- After a 5-minute cooldown, the circuit breaker resets and captures resume
// No configuration needed — circuit breaker is built into the SnapshotClient. // When tripped, you'll see a log message: // "[TraceKit] Circuit breaker open — pausing code monitoring for 5 minutes"
Behavior When Tripped
- All
tracekit_snapshot()calls become no-ops (zero overhead) - Distributed tracing and metrics continue to function normally
- The SDK automatically retries after the cooldown period
- No manual intervention required
Metrics
Track custom metrics using Counter, Gauge, and Histogram types. Metrics are automatically exported to TraceKit using the OTLP protocol.
Basic Usage
use TraceKit\Laravel\Facades\Tracekit; // Initialize metrics (typically in a service provider or route file) $requestCounter = Tracekit::counter('http.requests.total', ['service' => 'my-app']); $activeRequestsGauge = Tracekit::gauge('http.requests.active', ['service' => 'my-app']); $durationHistogram = Tracekit::histogram('http.request.duration', ['unit' => 'ms']); // Use metrics in your routes or controllers $requestCounter->inc(); // Increment by 1 $activeRequestsGauge->set(42); // Set to specific value $durationHistogram->record(125.5); // Record observation
Counter
Counters track monotonically increasing values (requests, errors, items processed):
$requestCounter = Tracekit::counter('http.requests.total', [ 'service' => 'my-app', 'environment' => config('app.env') ]); $requestCounter->inc(); // Increment by 1 $requestCounter->add(5); // Add specific amount
Gauge
Gauges track point-in-time values that can go up or down (active connections, queue size):
$activeUsersGauge = Tracekit::gauge('users.active', ['service' => 'my-app']); $activeUsersGauge->set(150); // Set to specific value $activeUsersGauge->inc(); // Increment by 1 $activeUsersGauge->dec(); // Decrement by 1
Histogram
Histograms track value distributions (request duration, payload sizes):
$durationHistogram = Tracekit::histogram('http.request.duration', ['unit' => 'ms']); $startTime = microtime(true); // ... do work ... $duration = (microtime(true) - $startTime) * 1000; $durationHistogram->record($duration);
HTTP Request Metrics Example
Track HTTP request metrics in your routes:
use TraceKit\Laravel\Facades\Tracekit; // Initialize metrics once (e.g., in routes/web.php or a service provider) $requestCounter = Tracekit::counter('http.requests.total', ['service' => 'my-app']); $activeRequestsGauge = Tracekit::gauge('http.requests.active', ['service' => 'my-app']); $durationHistogram = Tracekit::histogram('http.request.duration', ['unit' => 'ms']); $errorCounter = Tracekit::counter('http.errors.total', ['service' => 'my-app']); Route::get('/api/users', function () use ($requestCounter, $activeRequestsGauge, $durationHistogram) { $startTime = microtime(true); $activeRequestsGauge->inc(); try { $users = User::all(); return response()->json($users); } finally { $requestCounter->inc(); $activeRequestsGauge->dec(); $duration = (microtime(true) - $startTime) * 1000; $durationHistogram->record($duration); } });
Middleware Example
Track metrics across all routes using middleware:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use TraceKit\Laravel\Facades\Tracekit; class MetricsMiddleware { private $requestCounter; private $activeRequestsGauge; private $durationHistogram; private $errorCounter; public function __construct() { $this->requestCounter = Tracekit::counter('http.requests.total', ['service' => config('app.name')]); $this->activeRequestsGauge = Tracekit::gauge('http.requests.active', ['service' => config('app.name')]); $this->durationHistogram = Tracekit::histogram('http.request.duration', ['unit' => 'ms']); $this->errorCounter = Tracekit::counter('http.errors.total', ['service' => config('app.name')]); } public function handle(Request $request, Closure $next) { $startTime = microtime(true); $this->activeRequestsGauge->inc(); $response = $next($request); $this->requestCounter->inc(); $this->activeRequestsGauge->dec(); $duration = (microtime(true) - $startTime) * 1000; $this->durationHistogram->record($duration); if ($response->status() >= 400) { $this->errorCounter->inc(); } return $response; } }
Tags for Dimensional Analysis
Add tags to metrics for multi-dimensional analysis:
// Track requests by endpoint $requestCounter = Tracekit::counter('http.requests.total', [ 'service' => 'my-app', 'endpoint' => '/api/users', 'method' => 'GET' ]); // Track cache hits/misses $cacheHitCounter = Tracekit::counter('cache.hits', [ 'service' => 'my-app', 'cache_type' => 'redis' ]);
Common Use Cases
Database Metrics:
$queryCounter = Tracekit::counter('db.queries.total', ['database' => 'mysql']); $queryDuration = Tracekit::histogram('db.query.duration', ['unit' => 'ms']); DB::listen(function ($query) use ($queryCounter, $queryDuration) { $queryCounter->inc(); $queryDuration->record($query->time); });
Queue Metrics:
$jobCounter = Tracekit::counter('queue.jobs.total', ['queue' => 'default']); $jobDuration = Tracekit::histogram('queue.job.duration', ['unit' => 'ms']); // In your job class public function handle() { $startTime = microtime(true); // ... job logic ... $duration = (microtime(true) - $startTime) * 1000; $jobDuration->record($duration); $jobCounter->inc(); }
Business Metrics:
$ordersCounter = Tracekit::counter('orders.created', ['service' => 'my-app']); $revenueGauge = Tracekit::gauge('revenue.total', ['currency' => 'USD']); // Track business events $ordersCounter->inc(); $revenueGauge->set($totalRevenue);
Metric Export
Metrics are automatically buffered and exported to TraceKit:
- Buffer size: 100 metrics
- Export interval: 10 seconds
- Format: OTLP (OpenTelemetry Protocol)
Metrics are flushed automatically when the buffer is full or on application shutdown.
Automatic Service Discovery
TraceKit automatically instruments outgoing HTTP calls made with Laravel's HTTP client to create service dependency graphs.
How It Works
When your service makes an HTTP request using Laravel's Http facade:
- ✅ TraceKit creates a CLIENT span for the outgoing request
- ✅ Trace context is automatically injected into request headers (
traceparent) - ✅ The receiving service creates a SERVER span linked to your CLIENT span
- ✅ TraceKit maps the dependency: YourService → TargetService
Supported HTTP Clients
- ✅ Laravel HTTP Client (
Illuminate\Support\Facades\Http) - Automatic! - ✅ Guzzle (Laravel's HTTP client uses Guzzle under the hood)
Zero configuration required! Just use Laravel's HTTP client as normal:
use Illuminate\Support\Facades\Http; // All of these automatically create CLIENT spans: Http::get('http://payment-service/charge'); Http::post('http://inventory-service/reserve', ['item_id' => 123]); Http::withToken($token)->get('http://user-service/profile/123');
Service Name Detection
TraceKit intelligently extracts service names from URLs:
| URL | Extracted Service Name |
|---|---|
http://payment-service:3000 |
payment-service |
http://payment.internal |
payment |
http://payment.svc.cluster.local |
payment |
https://api.example.com |
api.example.com |
This works seamlessly with:
- Kubernetes service names
- Internal DNS names
- Docker Compose service names
- External APIs
Custom Service Name Mappings
For local development or when service names can't be inferred from hostnames, add service_name_mappings to your config/tracekit.php:
return [ // ... other config // Map localhost URLs to actual service names 'service_name_mappings' => [ 'localhost:8082' => 'payment-service', 'localhost:8083' => 'user-service', 'localhost:8084' => 'inventory-service', 'localhost:5001' => 'analytics-service', ], ];
Then make HTTP calls as normal:
use Illuminate\Support\Facades\Http; // Now requests to localhost:8082 will show as "payment-service" in the service graph $response = Http::get('http://localhost:8082/charge'); // -> Creates CLIENT span with peer.service = "payment-service"
This is especially useful when:
- Running microservices locally on different ports
- Using Docker Compose with localhost networking
- Testing distributed tracing in development
Example: Multi-Service Application
use Illuminate\Support\Facades\Http; Route::post('/checkout', function (Request $request) { // This HTTP call automatically creates a CLIENT span $paymentResponse = Http::post('http://payment-service/charge', [ 'amount' => $request->input('amount'), 'user_id' => auth()->id(), ]); // This one too! $inventoryResponse = Http::post('http://inventory-service/reserve', [ 'item_id' => $request->input('item_id'), ]); return response()->json([ 'status' => 'success', 'payment_id' => $paymentResponse['payment_id'], ]); });
Viewing Service Dependencies
Visit your TraceKit dashboard to see:
- Service Map: Visual graph showing which services call which
- Service List: Table of all services with health metrics
- Service Detail: Deep dive on individual services with upstream/downstream dependencies
Disabling Auto-Instrumentation
Add to your .env file:
TRACEKIT_AUTO_INSTRUMENT_HTTP_CLIENT=false
Or in config/tracekit.php:
return [ 'auto_instrument_http_client' => env('TRACEKIT_AUTO_INSTRUMENT_HTTP_CLIENT', true), ];
What Gets Traced?
Incoming HTTP Requests (SERVER spans)
Every HTTP request to your Laravel app is automatically traced with:
- Route name and URI
- HTTP method and status code
- Request duration
- User agent and client IP
- Query parameters
- Response size
Outgoing HTTP Requests (CLIENT spans)
Every HTTP request from your Laravel app is automatically traced with:
- Target URL and HTTP method
- HTTP status code
- Request duration
peer.serviceattribute for service dependency mapping
Database Queries
All database queries are traced with:
- Actual SQL with bound parameters
- Query duration
- Slow query highlighting (configurable threshold)
- Connection name and database
Queue Jobs
Laravel queue jobs are traced with:
- Job class name
- Queue name and connection
- Job status (completed/failed)
- Execution time
- Failure reasons and exceptions
Errors and Exceptions
All exceptions are automatically captured with:
- Exception type and message
- Full stack trace
- Request context
- User information
Coming Soon
The following features are planned for future releases:
- Cache Operations - Redis, Memcached, and file cache tracing
- Redis Commands - Direct Redis command tracing
- External HTTP Calls - Outgoing HTTP request tracking
Advanced Usage
Manual Tracing
You can create custom traces in your code:
use TraceKit\Laravel\TracekitClient; class MyController extends Controller { public function myMethod(TracekitClient $tracekit) { $span = $tracekit->startSpan('my-custom-operation', null, [ 'user.id' => auth()->id(), 'custom.attribute' => 'value', ]); try { // Your code here $result = $this->doSomething(); $tracekit->endSpan($span, [ 'result.count' => count($result), ]); } catch (\Exception $e) { $tracekit->recordException($span, $e); $tracekit->endSpan($span, [], 'ERROR'); throw $e; } } }
Environment-Based Configuration
Disable tracing in local development:
# .env.local TRACEKIT_ENABLED=false
Enable only specific features:
TRACEKIT_HTTP_ENABLED=true TRACEKIT_DATABASE_ENABLED=true TRACEKIT_CACHE_ENABLED=true TRACEKIT_QUEUE_ENABLED=false TRACEKIT_REDIS_ENABLED=true
Sampling
Trace only a percentage of requests (e.g., 10%):
TRACEKIT_SAMPLE_RATE=0.1
Performance
TraceKit APM is designed to have minimal performance impact:
- < 5% overhead on average request time
- Asynchronous trace sending (doesn't block responses)
- Automatic batching and compression
- Configurable sampling for high-traffic apps
Security
- Sensitive data handling: Query bindings can be disabled
- Secure transmission: HTTPS only
- API key authentication
- No PII collected by default
Disable query bindings:
TRACEKIT_INCLUDE_BINDINGS=false
Requirements
- PHP 8.1 or higher
- Laravel 10.x, 11.x, or 12.x
Support
- Documentation: https://app.tracekit.dev/docs
- Issues: https://github.com/Tracekit-Dev/laravel-apm/issues
- Email: support@tracekit.dev
License
MIT License. See LICENSE for details.
Credits
Built with ❤️ by the TraceKit team.