Let AI set up TraceKit for you

AI assistants can guide you through the entire setup process

Try AI Setup
Framework-Agnostic PHP Integration

PHP Language Integration

Add distributed tracing to any PHP application - vanilla PHP, Symfony, Slim, or any other framework. Built on OpenTelemetry for industry-standard observability.

PHP Distributed Tracing Guide

Go deeper with our PHP distributed tracing guide -- covering common pain points, production patterns, and code examples.

New: Frontend Observability

Looking for browser-side error tracking? Check out the new Browser SDK with React, Vue, Angular, Next.js, and Nuxt integrations via Framework Wrappers.

Prerequisites

  • PHP 8.1 or higher
  • Composer package manager
  • A TraceKit account (create one free)
  • A generated API key from the API Keys page

What Gets Traced Automatically?

ComponentSpan TypeCaptured AttributesAuto-Traced?
HTTP RequestsSERVERmethod, route, status_code, duration, client_ipYes (via TracekitClient middleware)
Database QueriesDBdb.system, db.statement, db.name, durationYes (via PDO wrapper)
External API CallsCLIENTmethod, url, status_code, durationYes (via HTTP client wrapper)
ExceptionsN/Aexception.type, exception.message, stack_traceYes (built-in)

Installation

1. Install via Composer

composer require tracekit/php-apm

2. Configure Environment

Create a .env file or set environment variables:

TRACEKIT_API_KEY=ctxio_your_generated_api_key_here
TRACEKIT_ENDPOINT=https://app.tracekit.dev/v1/traces
TRACEKIT_SERVICE_NAME=my-php-app

Basic Usage

Simple HTTP Request Tracing

<?php

require 'vendor/autoload.php';

use TraceKit\PHP\TracekitClient;

// Initialize TraceKit
$tracekit = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'service_name' => 'my-php-app',
    'endpoint' => 'https://app.tracekit.dev/v1/traces',
]);

// Start a trace
$span = $tracekit->startTrace('http-request', [
    'http.method' => $_SERVER['REQUEST_METHOD'],
    'http.url' => $_SERVER['REQUEST_URI'],
]);

try {
    // Your application logic here
    echo "Hello World!";

    $tracekit->endSpan($span, [
        'http.status_code' => 200,
    ]);
} catch (Exception $e) {
    $tracekit->recordException($span, $e);
    $tracekit->endSpan($span, [], 'ERROR');
    throw $e;
}

// Important: Flush traces before exit
$tracekit->flush();

Verify It Works

Start your application and make a few requests. Then open the Traces page in your TraceKit dashboard. You should see:

  • • SERVER spans for each incoming HTTP request with route and status
  • • CLIENT spans for outgoing HTTP calls (if instrumented)
  • • DB spans for database queries (if instrumented)

Traces typically appear within 30 seconds. If you don't see them, check the Troubleshooting section.

Code Monitoring (Live Debugging)

Debug Production Code Without Redeploying

Set non-breaking breakpoints and capture variable state, stack traces, and request context in production. No code changes or redeployment needed!

Learn more about Code Monitoring

Enable Code Monitoring

<?php

require 'vendor/autoload.php';

use TraceKit\PHP\TracekitClient;

// Initialize with code monitoring enabled
$tracekit = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'service_name' => 'my-php-app',
    'endpoint' => 'https://app.tracekit.dev/v1/traces',
    'code_monitoring_enabled' => true,
    'code_monitoring_max_depth' => 3,      // Nested array/object depth
    'code_monitoring_max_string' => 1000,  // Truncate long strings
]);

Capture Snapshots

Add checkpoints anywhere in your code to capture variable state and stack traces:

<?php

class CheckoutService
{
    private $tracekit;

    public function __construct($tracekit)
    {
        $this->tracekit = $tracekit;
    }

    public function processPayment($userId, $cart)
    {
        // Automatic snapshot capture with label
        $this->tracekit->captureSnapshot('checkout-validation', [
            'user_id' => $userId,
            'cart_items' => count($cart['items'] ?? []),
            'total_amount' => $cart['total'] ?? 0,
        ]);

        try {
            $result = $this->chargeCard($cart['total'], $userId);

            // Another checkpoint - captures on success
            $this->tracekit->captureSnapshot('payment-success', [
                'user_id' => $userId,
                'payment_id' => $result['payment_id'],
                'amount' => $result['amount'],
            ]);

            return $result;

        } catch (Exception $e) {
            // Automatic error capture
            $this->tracekit->captureSnapshot('payment-error', [
                'user_id' => $userId,
                'amount' => $cart['total'],
                'error' => $e->getMessage(),
            ]);

            throw $e;
        }
    }
}

Manual Polling Required

Since PHP doesn't have built-in background tasks, you need to poll for breakpoints manually:

<?php

// Option 1: Poll on every Nth request (recommended for low-traffic apps)
if (rand(1, 100) <= 5) { // 5% of requests
    $tracekit->pollBreakpoints();
}

// Option 2: Use a cron job (recommended for high-traffic apps)
// */1 * * * * php /path/to/poll-breakpoints.php

// poll-breakpoints.php
require 'vendor/autoload.php';

$tracekit = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'service_name' => 'my-php-app',
    'code_monitoring_enabled' => true,
]);

$tracekit->pollBreakpoints();

Auto-Registration

First call to captureSnapshot() automatically creates breakpoints

Variable Capture

Capture all local variables and request context at breakpoint

Stack Traces

Complete call stack with file names and line numbers

Production Safe

No performance impact when breakpoints are inactive

Production Safety

The PHP SDK includes built-in safety mechanisms to ensure code monitoring never impacts your production application:

PII Scrubbing

13 built-in patterns detect sensitive fields (password, token, secret, api_key, etc.) and replace values with typed [REDACTED:type] markers. Enabled by default — no configuration needed.

Crash Isolation

All SDK entry points wrap operations in catch(\Throwable) blocks. If the SDK encounters an error, your application continues running unaffected.

Circuit Breaker

After 3 consecutive failures within 60 seconds, the SDK enters a 5-minute cooldown period and stops making requests. Automatically recovers after cooldown. Laravel uses the Cache facade for cross-request persistence.

Remote Kill Switch

Instantly disable code monitoring from the dashboard. The kill signal propagates via SSE for CLI/worker processes or polling for web requests. No redeployment required.

Real-Time Updates

CLI and worker processes receive breakpoint updates and kill switch signals in real time via Server-Sent Events (SSE). Web requests use a polling fallback since PHP's process-per-request model does not support persistent connections.

Code Monitoring API

The following methods provide programmatic access to code monitoring capabilities:

Method Parameters Returns Description
getSnapshotClient() none ?SnapshotClient Returns the snapshot client if code monitoring is enabled, or null otherwise. Advanced.
isCodeMonitoringEnabled() none bool Returns whether code monitoring is active. Use to guard snapshot capture calls in performance-sensitive paths.

Capture Configuration Options

Option Type Default Description
code_monitoring_enabled bool false Enable or disable code monitoring. Must be explicitly set to true.
code_monitoring_max_depth int 5 Maximum depth for nested object/array serialization in captured variables.
code_monitoring_max_string int 1024 Maximum string length before truncation in captured variable values.
pii_scrubbing_enabled bool true Enable PII scrubbing on captured data. Uses 13 built-in patterns to detect and redact sensitive fields with typed [REDACTED:type] markers.
circuit_breaker_threshold int 3 Number of consecutive failures before the circuit breaker trips and enters cooldown.
circuit_breaker_cooldown int 300 Cooldown period in seconds after the circuit breaker trips. Defaults to 5 minutes.

End-to-End Workflow

1

Enable Code Monitoring

Add code_monitoring_enabled to your TracekitClient configuration. Code monitoring defaults to disabled in PHP -- you must explicitly enable it.

$client = new TracekitClient([
    'api_key'                    => getenv('TRACEKIT_API_KEY'),
    'service_name'               => 'my-php-app',
    'code_monitoring_enabled'    => true,

    // Optional: fine-tune capture depth and string length
    'code_monitoring_max_depth'  => 5,
    'code_monitoring_max_string' => 1024,
]);
2

Add Snapshot Capture Points

Place captureSnapshot() calls at points of interest. This is a synchronous call that checks for active breakpoints and captures variable state.

$client->captureSnapshot('order-checkout', [
    'order_id'  => $order->id,
    'total'     => $order->total,
    'items'     => count($order->items),
    'customer'  => $customer->email,
]);
3

Deploy and Verify Traces

Deploy your application and confirm traces are flowing. Navigate to the /traces dashboard and verify your service appears with recent trace data.

4

Navigate to Code Monitoring

Go to /snapshots and click the "Browse Code" tab. You will see auto-discovered files and functions from your traces.

5

Set Breakpoints

Breakpoints are auto-registered on the first captureSnapshot() call. You can also manually set breakpoints via the UI using the "Set Breakpoint" button.

⚠️

Long-Running Processes

For workers, daemons, and queue consumers, you must call $client->pollBreakpoints() periodically since PHP does not have background tasks. Web requests auto-poll on client construction, but long-running processes need explicit polling to pick up new breakpoints.

6

Trigger Snapshot Capture

Make a request that hits a code path containing captureSnapshot(). The SDK uses debug_backtrace() for file and line detection, capturing the full call stack along with your variables.

7

View Captured Snapshot

Go to /snapshots and click the captured snapshot. You can inspect:

  • Variables -- the data you passed to captureSnapshot
  • Stack Trace -- complete call stack with file names and line numbers
  • Request Context -- HTTP method, URL, headers, client IP
  • Security Flags -- any sensitive data detected and redacted

Framework Integration

Symfony

Create an event listener to automatically trace all HTTP requests:

<?php

namespace App\EventListener;

use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use TraceKit\PHP\TracekitClient;

class TracekitListener
{
    private TracekitClient $tracekit;
    private $currentSpan;

    public function __construct()
    {
        $this->tracekit = new TracekitClient([
            'api_key' => $_ENV['TRACEKIT_API_KEY'],
            'service_name' => 'symfony-app',
            'code_monitoring_enabled' => true,  // Enable code monitoring
        ]);
    }

    public function onKernelRequest(RequestEvent $event)
    {
        if (!$event->isMainRequest()) {
            return;
        }

        // Poll for breakpoints on 5% of requests
        if (rand(1, 20) === 1) {
            $this->tracekit->pollBreakpoints();
        }

        $request = $event->getRequest();
        $this->currentSpan = $this->tracekit->startTrace('http-request', [
            'http.method' => $request->getMethod(),
            'http.url' => $request->getRequestUri(),
            'http.route' => $request->attributes->get('_route'),
        ]);

        // Capture request start snapshot
        $this->tracekit->captureSnapshot('request-start', [
            'route' => $request->attributes->get('_route'),
            'method' => $request->getMethod(),
        ]);
    }

    public function onKernelResponse(ResponseEvent $event)
    {
        if (!$event->isMainRequest() || !$this->currentSpan) {
            return;
        }

        $this->tracekit->endSpan($this->currentSpan, [
            'http.status_code' => $event->getResponse()->getStatusCode(),
        ]);
        $this->tracekit->flush();
    }

    public function onKernelException(ExceptionEvent $event)
    {
        if ($this->currentSpan) {
            $this->tracekit->recordException($this->currentSpan, $event->getThrowable());
            
            // Capture exception snapshot
            $this->tracekit->captureSnapshot('exception-handler', [
                'exception' => get_class($event->getThrowable()),
                'message' => $event->getThrowable()->getMessage(),
            ]);
            
            $this->tracekit->endSpan($this->currentSpan, [], 'ERROR');
            $this->tracekit->flush();
        }
    }
}

Slim Framework

Use middleware to trace requests:

<?php

use Slim\Factory\AppFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use TraceKit\PHP\TracekitClient;

require 'vendor/autoload.php';

$tracekit = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'service_name' => 'slim-app',
    'endpoint' => 'https://app.tracekit.dev/v1/traces',
    'code_monitoring_enabled' => true,  // Enable code monitoring
]);

$app = AppFactory::create();

// Tracing & monitoring middleware
$app->add(function (Request $request, $handler) use ($tracekit) {
    // Poll for breakpoints on 5% of requests
    if (rand(1, 20) === 1) {
        $tracekit->pollBreakpoints();
    }

    $span = $tracekit->startTrace('http-request', [
        'http.method' => $request->getMethod(),
        'http.url' => (string) $request->getUri(),
    ]);

    // Capture request snapshot
    $tracekit->captureSnapshot('middleware-start', [
        'path' => $request->getUri()->getPath(),
        'method' => $request->getMethod(),
    ]);

    try {
        $response = $handler->handle($request);

        $tracekit->endSpan($span, [
            'http.status_code' => $response->getStatusCode(),
        ]);

        $tracekit->flush();
        return $response;
    } catch (Exception $e) {
        $tracekit->recordException($span, $e);
        
        // Capture exception snapshot
        $tracekit->captureSnapshot('middleware-error', [
            'exception' => get_class($e),
            'message' => $e->getMessage(),
        ]);
        
        $tracekit->endSpan($span, [], 'ERROR');
        $tracekit->flush();
        throw $e;
    }
});

$app->get('/hello/{name}', function (Request $request, Response $response, $args) use ($tracekit) {
    // Capture route handler snapshot
    $tracekit->captureSnapshot('hello-route', [
        'name' => $args['name'],
    ]);

    $response->getBody()->write("Hello, " . $args['name']);
    return $response;
});

$app->run();

Vanilla PHP

For vanilla PHP applications, wrap your application logic:

<?php

require 'vendor/autoload.php';

use TraceKit\PHP\TracekitClient;

$tracekit = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'service_name' => 'my-app',
    'endpoint' => 'https://app.tracekit.dev/v1/traces',
    'code_monitoring_enabled' => true,  // Enable code monitoring
]);

// Poll for breakpoints on 5% of requests
if (rand(1, 20) === 1) {
    $tracekit->pollBreakpoints();
}

$span = $tracekit->startTrace('http-request', [
    'http.method' => $_SERVER['REQUEST_METHOD'],
    'http.url' => $_SERVER['REQUEST_URI'],
]);

try {
    // Capture snapshot at app start
    $tracekit->captureSnapshot('app-start', [
        'uri' => $_SERVER['REQUEST_URI'],
        'method' => $_SERVER['REQUEST_METHOD'],
    ]);

    // Your application logic
    echo "Hello World!";

    $tracekit->endSpan($span, [
        'http.status_code' => 200,
    ]);
} catch (Exception $e) {
    $tracekit->recordException($span, $e);
    
    // Capture exception snapshot
    $tracekit->captureSnapshot('app-error', [
        'exception' => get_class($e),
        'message' => $e->getMessage(),
    ]);
    
    $tracekit->endSpan($span, [], 'ERROR');
}

$tracekit->flush();

Auto-Instrumentation

PHP tracing typically requires manual instrumentation for most operations.

HTTP Client API

The PHP SDK provides wrappers for instrumenting outgoing HTTP calls and extracting client information:

Method Parameters Returns Description
getHttpClientInstrumentation() none ?HttpClientInstrumentation Returns the Guzzle/cURL instrumentation wrapper for outgoing HTTP calls. Returns null if not configured. Advanced.
extractClientIp($headers) ?array $headers = null ?string Extracts client IP from request headers (checks X-Forwarded-For, X-Real-IP, REMOTE_ADDR). Pass null to use $_SERVER.

LLM Instrumentation

TraceKit automatically instruments OpenAI and Anthropic API calls when detected. LLM calls appear as spans with OTel GenAI semantic convention attributes.

Zero-config auto-instrumentation

If your PHP app uses Guzzle for OpenAI or Anthropic API calls, TraceKit instruments them automatically via middleware. No code changes required.

Captured Attributes

AttributeDescription
gen_ai.systemProvider name (openai, anthropic)
gen_ai.request.modelModel name (gpt-4o, claude-sonnet-4-20250514, etc.)
gen_ai.usage.input_tokensPrompt token count
gen_ai.usage.output_tokensCompletion token count
gen_ai.response.finish_reasonsFinish reason (stop, end_turn, tool_calls)

Configuration

PHP
$client = new TracekitClient([ 'apiKey' => getenv('TRACEKIT_API_KEY'), 'serviceName' => 'my-php-service', 'llm' => [ 'enabled' => true,        // Master toggle 'openai' => true,         // OpenAI instrumentation 'anthropic' => true,      // Anthropic instrumentation 'captureContent' => false, // Capture prompts/completions (off by default) ], ]);

Environment Variable Override

Use TRACEKIT_LLM_CAPTURE_CONTENT=true to enable prompt/completion capture without code changes. Useful for enabling in staging but not production.

Streaming Support

Streaming responses produce a single span that covers the entire stream. Token counts are accumulated from the final chunk. No special configuration needed.

LLM Dashboard

View LLM cost, token usage, and latency metrics on the dedicated LLM Observability dashboard at /ai/llm in your TraceKit instance.

Local UI (Development Mode)

Debug your PHP application locally without creating an account. TraceKit Local UI runs on your machine at http://localhost:9999 and automatically receives traces when you run your app in development mode.

Automatic Detection

The PHP SDK automatically detects when Local UI is running on port 9999 and sends traces to both Local UI and cloud (if you have an API key configured).

Quick Start

1. Install the Local UI:

npm install -g @tracekit/local-ui

2. Start the Local UI:

tracekit-local

3. Run your app in development mode:

ENV=development php -S localhost:8000

4. Open your browser:

http://localhost:9999

Features

Auto-Detection

SDK checks for Local UI at localhost:9999 on startup

Real-Time Updates

See traces instantly with WebSocket live updates

Development Only

Only activates when ENV=development

Works Offline

No internet connection required - everything runs locally

Benefits

  • See your first trace in under 60 seconds
  • Debug locally without switching to the cloud dashboard
  • Stay in your flow - everything runs on your machine
  • Works completely offline
  • Perfect for development and demos

Troubleshooting

If traces aren't appearing in Local UI, check:

  • Local UI is running (curl http://localhost:9999/api/health)
  • ENV=development is set
  • SDK version is v1.0.4 or higher
  • Check console for " Local UI detected" message

Service Discovery

TraceKit automatically instruments outgoing HTTP calls to create service dependency graphs. When your service makes an HTTP request to another service, TraceKit creates CLIENT spans and injects trace context headers.

Custom Service Name Mappings

For local development or when service names can't be inferred from hostnames, configure service name mappings:

<?php

use TraceKit\PHP\TracekitClient;

$tracekit = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'service_name' => 'my-service',
    // Map localhost URLs to actual service names
    'service_name_mappings' => [
        'localhost:8082' => 'payment-service',
        'localhost:8083' => 'user-service',
        'localhost:8084' => 'inventory-service',
    ],
]);

// Now requests to localhost:8082 will show as "payment-service"
$response = file_get_contents('http://localhost:8082/charge');
// -> Creates CLIENT span with peer.service = "payment-service"

This maps localhost:8082 to "payment-service" in your service graph.

Service Name Detection

TraceKit intelligently extracts service names from URLs:

URLExtracted Service Name
http://payment-service:3000payment-service
http://payment.internalpayment
http://payment.svc.cluster.localpayment
https://api.example.comapi.example.com

Viewing Service Dependencies

Visit your TraceKit dashboard to see the Service Map - a visual graph showing which services call which, with health metrics and latency data.

Manual Instrumentation

Database Queries

<?php

function getUserById($tracekit, $userId) {
    $span = $tracekit->startSpan('db.query.users', [
        'db.system' => 'mysql',
        'db.operation' => 'SELECT',
        'user.id' => $userId,
    ]);

    try {
        $pdo = new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');
        $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$userId]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        $tracekit->endSpan($span, [
            'db.rows_affected' => $stmt->rowCount(),
        ]);

        return $user;
    } catch (PDOException $e) {
        $tracekit->recordException($span, $e);
        $tracekit->endSpan($span, [], 'ERROR');
        throw $e;
    }
}

External API Calls

<?php

function fetchExternalData($tracekit, $url) {
    $span = $tracekit->startSpan('http.client.get', [
        'http.url' => $url,
        'http.method' => 'GET',
    ]);

    try {
        $response = file_get_contents($url);
        $data = json_decode($response, true);

        $tracekit->endSpan($span, [
            'http.status_code' => 200,
            'response.size' => strlen($response),
        ]);

        return $data;
    } catch (Exception $e) {
        $tracekit->recordException($span, $e);
        $tracekit->endSpan($span, [], 'ERROR');
        throw $e;
    }
}

Nested Spans

<?php

function processOrder($tracekit, $orderId) {
    $orderSpan = $tracekit->startSpan('process-order', [
        'order.id' => $orderId,
    ]);

    try {
        // Validate order
        $validationSpan = $tracekit->startSpan('validate-order', [
            'order.id' => $orderId,
        ]);
        $valid = validateOrder($orderId);
        $tracekit->endSpan($validationSpan, ['valid' => $valid]);

        if (!$valid) {
            throw new Exception('Invalid order');
        }

        // Process payment
        $paymentSpan = $tracekit->startSpan('process-payment', [
            'order.id' => $orderId,
        ]);
        $paymentResult = processPayment($orderId);
        $tracekit->endSpan($paymentSpan, ['payment.status' => $paymentResult]);

        $tracekit->endSpan($orderSpan, [
            'order.status' => 'completed',
        ]);

        return true;
    } catch (Exception $e) {
        $tracekit->recordException($orderSpan, $e);
        $tracekit->endSpan($orderSpan, [], 'ERROR');
        throw $e;
    }
}

Tracing API Reference

Complete reference for distributed tracing methods available on TracekitClient:

Method Parameters Returns Description
extractTraceparent($headers) array $headers ContextInterface Extracts W3C Trace Context from incoming request headers for distributed tracing. Returns a context object to pass as parent to startServerSpan().
startServerSpan($op, $attrs, $ctx) string $operationName, array $attributes = [], ?ContextInterface $parentContext = null array Creates a SERVER span with optional parent context from extractTraceparent(). Returns span data array to pass to endSpan().
addEvent($spanData, $name, $attrs) array $spanData, string $name, array $attributes = [] void Records a timestamped event on the current span. Use for logging significant moments within a trace (e.g., cache hit, validation passed).

Distributed Tracing Example

Receive trace context from an upstream service and create linked spans:

// Receive trace context from upstream service
$parentContext = $client->extractTraceparent(getallheaders());

// Create a server span linked to the parent trace
$spanData = $client->startServerSpan(
    'handle-webhook',
    ['webhook.type' => $type],
    $parentContext
);

// Add events as you process
$client->addEvent($spanData, 'validation.passed', ['order.id' => $orderId]);

// ... process webhook

$client->endSpan($spanData);
$client->flush(); // Important for PHP scripts!

Lifecycle API Reference

Methods for managing the SDK lifecycle, sampling, and the underlying tracer:

Method Parameters Returns Description
getTracer() none TracerInterface Returns the underlying OpenTelemetry Tracer for advanced instrumentation scenarios.
shouldSample() none bool Returns whether the current request should be sampled based on the configured sample_rate.
isEnabled() none bool Returns whether the SDK is currently enabled. Use to guard expensive instrumentation code.
shutdown() none void Gracefully shuts down the SDK and flushes any remaining trace/metric data. Call before process exit.

Environment Variables

Store your API key and configuration in environment variables as shown in the installation section above.

All configuration options available for the PHP SDK:

Option Type Default Env Variable Description
api_key string "" TRACEKIT_API_KEY Your TraceKit API key for authentication
service_name string "php-app" TRACEKIT_SERVICE_NAME Name of your service in the trace dashboard
endpoint string "app.tracekit.dev" TRACEKIT_ENDPOINT TraceKit collector endpoint URL
traces_path string "/v1/traces" TRACEKIT_TRACES_PATH HTTP path for trace data export
metrics_path string "/v1/metrics" TRACEKIT_METRICS_PATH HTTP path for metrics data export
enabled bool true TRACEKIT_ENABLED Enable or disable tracing globally
sample_rate float 1.0 TRACEKIT_SAMPLE_RATE Trace sampling rate (0.0 to 1.0, where 1.0 = 100%)
service_name_mappings array [] - Map host:port to service names for service discovery
code_monitoring_enabled bool false TRACEKIT_CODE_MONITORING_ENABLED Enable live code debugging / snapshot capture
code_monitoring_max_depth int 3 TRACEKIT_CODE_MONITORING_MAX_DEPTH Max variable inspection depth for snapshots
code_monitoring_max_string int 1000 TRACEKIT_CODE_MONITORING_MAX_STRING Max string length captured in snapshots
suppress_errors bool true TRACEKIT_SUPPRESS_ERRORS Suppress SDK errors to prevent app crashes

Note: The PHP SDK does not auto-read environment variables. Read them with getenv() and pass to the TracekitClient constructor.

Configuration Options

Customize the TracekitClient with these configuration options:

<?php

$tracekit = new TracekitClient([
    // Required: Your TraceKit API key
    'api_key' => getenv('TRACEKIT_API_KEY'),

    // Optional: Service name (default: 'php-app')
    'service_name' => 'my-service',

    // Optional: TraceKit endpoint (default: 'https://app.tracekit.dev/v1/traces')
    'endpoint' => 'https://app.tracekit.dev/v1/traces',

    // Optional: Enable/disable tracing (default: true)
    'enabled' => getenv('APP_ENV') === 'production',

    // Optional: Sample rate 0.0-1.0 (default: 1.0 = 100%)
    'sample_rate' => 0.5, // Trace 50% of requests

    // Optional: Enable code monitoring (default: false)
    'code_monitoring_enabled' => true,
    'code_monitoring_max_depth' => 3,      // Nested array/object depth
    'code_monitoring_max_string' => 1000,  // Truncate long strings
]);

Custom Metrics

Track custom metrics like request counts, queue sizes, and response times using the TraceKit metrics API.

Counter

Track monotonically increasing values (requests, events):

use TraceKit\PHP\MetricsRegistry;

// Initialize the registry
$metrics = new MetricsRegistry($endpoint, $apiKey, 'my-service');

// Create a counter with optional tags
$counter = $metrics->counter('http.requests.total', [
    'service' => 'api',
    'method' => 'GET',
]);

// Increment by 1
$counter->inc();

// Add a specific value
$counter->add(5);

Gauge

Track values that can go up or down (queue size, connections):

// Create a gauge
$gauge = $metrics->gauge('http.connections.active');

// Set to specific value
$gauge->set(42);

// Increment/decrement
$gauge->inc();
$gauge->dec();

Histogram

Track value distributions (latencies, sizes):

// Create a histogram with tags
$histogram = $metrics->histogram('http.request.duration', [
    'unit' => 'ms',
]);

// Record values
$histogram->record(45.2);
$histogram->record(123.5);

Troubleshooting

Traces not appearing?

Cause: PHP scripts terminate after each request; unflushed spans are lost.

Fix:

  • Call $client->flush() before script termination or in a shutdown handler: register_shutdown_function([$client, 'flush'])
  • Verify API key is correct
  • Check that enabled is true in the config array

Composer dependency issues?

Cause: PHP version or package version conflicts prevent installation.

Fix:

  • Verify PHP 8.1+: php -v
  • Update Composer: composer self-update
  • Clear cache: composer clear-cache
  • If version conflicts persist, try composer update --with-all-dependencies

Code monitoring not working?

Cause: Code monitoring is disabled by default in the PHP SDK.

Fix:

  • Set 'code_monitoring_enabled' => true in the config array
  • Add $client->captureSnapshot('label') calls
  • Note that code_monitoring_max_depth (default 3) limits captured variable nesting -- increase if needed

Authentication errors (401/403)?

Cause: API key is missing, empty, or contains whitespace.

Fix:

  • Verify with echo getenv('TRACEKIT_API_KEY');
  • The PHP SDK defaults api_key to empty string -- passing no key silently fails
  • Regenerate in dashboard if expired

Connection refused errors?

Cause: The TraceKit endpoint is unreachable or suppress_errors is hiding the real error.

Fix:

  • Temporarily set 'suppress_errors' => false to see full OTel error output
  • Test with curl -X POST https://app.tracekit.dev/v1/traces (expect 401)
  • Check php.ini for allow_url_fopen if using HTTP transport

Complete Example

See the framework integration examples above for complete working code.

🔄 Migrating from OpenTelemetry

TraceKit wraps OpenTelemetry internally, so you get the same standards-based trace data with significantly less setup code. Here's how to migrate from a raw OpenTelemetry setup to TraceKit.

Before vs After

Before: Raw OpenTelemetry ~20 lines
<?php
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Resource\ResourceInfo;

$transport = (new OtlpHttpTransportFactory())->create(
    'https://api.tracekit.io/v1/traces',
    'application/json',
    ['Authorization' => 'Bearer ' . $apiKey]
);
$exporter = new \OpenTelemetry\Contrib\Otlp\SpanExporter($transport);
$resource = ResourceInfo::create(
    Attributes::create(['service.name' => 'my-service'])
);
$tracerProvider = TracerProvider::builder()
    ->addSpanProcessor(new SimpleSpanProcessor($exporter))
    ->setResource($resource)
    ->build();
$tracer = $tracerProvider->getTracer('my-app');
After: TraceKit SDK 4 lines
<?php
$tracekit = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'service_name' => 'my-service',
]);

// At end of request:
$tracekit->flush();

Migration Steps

1

Install the SDK: composer require tracekit/php-sdk

2

Replace init code: Remove all OTel use statements and TracerProvider builder. Replace with new TracekitClient([...])

3

Replace manual spans: Use SDK wrapper methods instead of raw span creation

4

Add flush: Call $tracekit->flush() at the end of every request (PHP shared-nothing lifecycle)

5

Remove OTel packages: composer remove open-telemetry/sdk open-telemetry/exporter-otlp

6

Verify: Make a request and check the Traces page for incoming data

Key Migration Benefits

  • 20 lines to 4 lines — no more boilerplate for transport, exporter, resources
  • No OTel dependency management — TraceKit handles version pinning internally
  • Built-in code monitoring — not available with raw OpenTelemetry
  • Built-in security scanning — automatic variable redaction on snapshots
  • PDO and HTTP wrappers — automatic DB and external call tracing

Performance Overhead

TraceKit is built on OpenTelemetry's efficient batch processing pipeline. The SDK adds minimal overhead to your PHP application.

Low

Request Tracing

< 2ms per request

Spans are batched and exported asynchronously.

Negligible

Code Monitoring (Idle)

Zero overhead

No performance impact when no active breakpoints.

Low

Code Monitoring (Capture)

< 5ms per snapshot

Includes variable serialization and security scanning.

Negligible

Memory Footprint

~5-10 MB

SDK runtime and span buffer.

Low

SDK Initialization

< 100ms per request

PHP's per-request lifecycle means initialization occurs on every request. The overhead is amortized across the request but occurs each time.

Note: Performance characteristics are typical for production workloads and may vary with application complexity, request volume, and number of instrumented libraries. Use sampling configuration to reduce overhead in high-traffic services.

Best Practices

DO: Initialize tracing before loading routes/handlers

Call TracekitClient::init() early in your bootstrap or entry script before route handlers execute.

DO: Use environment variables for API keys

Store your API key in TRACEKIT_API_KEY rather than hardcoding it. The SDK reads this automatically.

DO: Call $tracekit->flush() at end of every request

PHP's shared-nothing architecture means each request is independent. Always flush pending spans before the response is sent to avoid data loss.

// At the end of your request handler
$tracekit->flush();
// Send response

DO: Use the SDK HTTP client wrapper for auto-traced outbound calls

Use the TraceKit HTTP client wrapper instead of raw cURL to get automatic span creation for outbound HTTP requests.

DO: Enable code monitoring in staging first

Test breakpoint capture and snapshot behavior in a staging environment before rolling out to production.

DO: Use sampling in high-traffic services

Set TRACEKIT_SAMPLING_RATE to a value below 1.0 for services handling thousands of requests per second to reduce overhead without losing visibility.

DO: Set meaningful service names

Use TRACEKIT_SERVICE_NAME to give your service a descriptive name that makes it easy to identify in the trace viewer.

DON'T: Rely on __destruct() for trace flushing

PHP destructors are not guaranteed to run in all SAPI modes (e.g., PHP-FPM). Always call flush() explicitly before the response is sent.

DON'T: Initialize TraceKit in a loop or inside request handlers

Initialize once per request lifecycle in your bootstrap. Calling init inside a loop or handler creates multiple SDK instances and wastes resources.

DON'T: Create spans for every function

Trace boundaries like HTTP handlers, database calls, and external service calls. Instrumenting internal helper functions adds noise and overhead without useful insight.

DON'T: Add high-cardinality attributes

Avoid using user IDs, request IDs, or session tokens as span attributes. These create excessive unique time series and degrade query performance.

DON'T: Disable TLS in production

The TRACEKIT_INSECURE flag is for local development only. Always use TLS when sending traces to TraceKit in production.

Copilot

No conversations yet

TraceKit Copilot

Ask about services, traces, alerts, snapshots, and LLM usage.

Copilot uses AI to analyze your APM data. Responses may not always be accurate.

Try TraceKit in 10 seconds

Explore real traces, dashboards, and live code monitoring. No signup needed.

Sign Up Free
No credit card No signup Real data