Skip to main content
This guide walks you through a minimal setup and shows you what auto-instrumentation looks like in practice. By the end you will have traces appearing in your backend (or printed to stdout).
1

Install the package

If you haven’t already, install the package via Composer:
composer require keepsuit/laravel-opentelemetry
Publish the config file:
php artisan vendor:publish --provider="Keepsuit\LaravelOpenTelemetry\LaravelOpenTelemetryServiceProvider" --tag="opentelemetry-config"
2

Add the minimal .env configuration

Add the following variables to your .env file:
.env
OTEL_SERVICE_NAME=my-laravel-app
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME is how your service is identified in your observability backend. OTEL_EXPORTER_OTLP_ENDPOINT is the address of your OpenTelemetry Collector or a compatible backend.
If you don’t have a collector running locally, use the console exporter to print spans to stdout during development:
.env
OTEL_TRACES_EXPORTER=console
You will see a detailed JSON representation of each span printed after every request.
3

Make a request and verify auto-tracing

Start your development server and make any HTTP request:
php artisan serve
curl http://localhost:8000
The HTTP server instrumentation automatically traces every incoming request. If you are using the console exporter, you will see span output in the terminal running php artisan serve. If you are using an OTLP backend, open it and search for your service name — the trace should appear within a few seconds.A typical auto-traced request produces spans for:
  • The HTTP request itself (GET /)
  • Any database queries executed during the request
  • Any Redis commands, cache operations, or events fired
  • Any views rendered
4

Create a custom span

Use the Tracer facade to create a custom span around any piece of code:
use Keepsuit\LaravelOpenTelemetry\Facades\Tracer;

Tracer::newSpan('my custom trace')->measure(function () {
    // Your code here — all child spans will be nested under this one
});
The measure method starts the span, activates it as the current span (so any spans created inside inherit it as their parent), runs the callback, then ends the span automatically.If you need the span open across multiple statements, use start and end manually:
use Keepsuit\LaravelOpenTelemetry\Facades\Tracer;

$span = Tracer::newSpan('my custom trace')->start();
$scope = $span->activate();

// Your code here

$scope->detach();
$span->end();
5

Read the current trace ID

You can retrieve the active trace ID at any point, for example to include it in an API response or log message:
use Keepsuit\LaravelOpenTelemetry\Facades\Tracer;

$traceId = Tracer::traceId();
The trace ID is a 32-character hex string uniquely identifying the current trace. When logs.inject_trace_id is enabled (the default), it is also automatically injected into the Laravel log context under the trace_id key.

What happens automatically

With the default configuration and no additional code, the following is traced for every HTTP request:
  • HTTP span — method, route, status code, and duration
  • Database spans — every SQL query with operation name and duration
  • Redis spans — every Redis command
  • Cache events — hits, misses, and writes recorded as events on the active span
  • Laravel events — framework events recorded on the active span
  • View spans — each Blade view rendered during the request
Queue jobs are traced as producer/consumer span pairs. The trace context is propagated from the dispatch site to the worker.

Next steps

HTTP server instrumentation

Learn how to exclude paths, filter headers, and read HTTP server metrics.

Traces

Sampling, tail sampling, custom span processors, and the full Tracer facade API.

Build docs developers (and LLMs) love