PHPackages                             lookout/tracing - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. lookout/tracing

ActiveLibrary

lookout/tracing
===============

Distributed tracing, sampled performance spans (limits, Laravel collectors), optional browser RUM beacons, breadcrumbs, structured logs and custom metrics ingest, exception reporting with enrichment pipeline, cron check-ins, and profiling ingest for Lookout.

00PHP

Since Mar 27Pushed 1mo agoCompare

[ Source](https://github.com/shaferllc/lookout-tracing)[ Packagist](https://packagist.org/packages/lookout/tracing)[ RSS](/packages/lookout-tracing/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

lookout/tracing
===============

[](#lookouttracing)

PHP library for **Lookout** distributed tracing with **Sentry-compatible** headers and manual instrumentation. You do **not** need the Sentry SDK; APIs mirror [Sentry PHP tracing instrumentation](https://docs.sentry.io/platforms/php/tracing/instrumentation/) and [trace propagation](https://docs.sentry.io/platforms/php/tracing/trace-propagation/) so existing patterns transfer easily.

Install
-------

[](#install)

```
composer require lookout/tracing
```

(This repository vendors the package from `packages/lookout-tracing` via a Composer path repository.)

Propagation
-----------

[](#propagation)

- **Incoming:** parse `sentry-trace` and `baggage` (e.g. from `PSR-7` request headers or Laravel’s `Request`).
- **Outgoing:** add the same headers to downstream HTTP calls so other services can continue the trace.

```
use Lookout\Tracing\Tracer;

Tracer::instance()->continueTrace(
    $request->getHeaderLine('sentry-trace'),
    $request->getHeaderLine('baggage'),
);

$headers = Tracer::instance()->outgoingTraceHeaders();
// [ 'sentry-trace' => '...', 'baggage' => '...' ]
```

HTML meta tags for browser SDKs:

```
use Lookout\Tracing\HtmlTraceMeta;

echo HtmlTraceMeta::render();
```

Custom instrumentation
----------------------

[](#custom-instrumentation)

```
use Lookout\Tracing\SpanOperation;
use Lookout\Tracing\Tracing;

$tx = Tracing::startTransaction('GET /orders', SpanOperation::HTTP_SERVER);

Tracing::trace(function () {
    // …
}, SpanOperation::HTTP_CLIENT, 'GET https://api.example.com/v1/orders');

$tx->finish();
```

Common `op` values are defined on `Lookout\Tracing\SpanOperation` (`http.server`, `http.client`, `db.query`, `cache.get`, `queue.publish`, etc.).

Lookout ingest
--------------

[](#lookout-ingest)

- **`Tracer::errorIngestTraceFields()`** — `trace_id`, `span_id`, `parent_span_id`, `transaction` for your error JSON body to `POST /api/ingest`.
- **`Tracer::errorIngestPerformanceGroupingHints()`** — when **`reporting.performance_grouping.enabled`** is true (env **`LOOKOUT_REPORT_PERFORMANCE_GROUPING`**) and **`performance_enabled`** recorded spans in the same request, may add **`grouping_slow_path`** and **`grouping_db_time_ms`** so Lookout can fingerprint slow / DB-heavy errors separately (see Lookout ingest docs).
- **`Tracer::configure([...])`** + **`Tracer::flush()`** — send finished spans to `POST /api/ingest/trace` (set `api_key`, `base_uri`, optional `environment` / `release`). Use **`Tracer::flushWithResult()`** (or **`Tracing::flushWithResult()`**) when you need the HTTP **status** (e.g. **403** if the Lookout project disabled trace ingest).

Structured logs (Sentry-style)
------------------------------

[](#structured-logs-sentry-style)

Similar in spirit to [Sentry PHP logs](https://docs.sentry.io/platforms/php/logs/): **`lookout_logger()->info('User %s logged in', ['alice'])`**, optional **`flush()`**, and a **Monolog** handler. Rows go to **`POST /api/ingest/log`** with the same **`api_key`** / **`base_uri`** as tracing; enable with **`LOOKOUT_LOGS_ENABLED=true`** (Laravel: `config/lookout-tracing.php` → **`logging.enabled`**). Laravel registers a **terminating** flush when **`logging.enabled`** and **`logging.flush_on_terminate`** are true. Long workers should call **`lookout_logger()->flush()`** on a timer or after batches.

```
lookout_logger()->info('order placed', null, ['order_id' => '42']);
lookout_logger()->flush();
```

```
use Lookout\Tracing\Logging\Monolog\LookoutMonologHandler;
use Monolog\Logger;

$log = new Logger('app');
$log->pushHandler(new LookoutMonologHandler());
```

Custom metrics (Sentry-style)
-----------------------------

[](#custom-metrics-sentry-style)

Similar in spirit to [Sentry PHP metrics](https://docs.sentry.io/platforms/php/metrics/): **`lookout_metrics()->count('orders.completed', 1)`**, **`gauge()`**, **`distribution()`**, optional **`MetricUnit`**, and **`flush()`**. Samples go to **`POST /api/ingest/metric`**; the active **`trace_id`** is attached when a transaction is in flight so the Lookout UI can correlate rollups with traces. Enable with **`LOOKOUT_METRICS_ENABLED=true`** (Laravel: **`metrics.enabled`**). Laravel flushes on **terminating** when **`metrics.enabled`** and **`metrics.flush_on_terminate`** are true.

Optional **`MetricsIngestClient::configure(['before_send_metric' => fn (array $row): ?array => $row])`** drops or mutates rows before enqueue (return **`null`** to skip), like Sentry’s **`before_send_metric`**.

```
use Lookout\Tracing\Metrics\MetricUnit;

lookout_metrics()->count('button.click', 5, ['plan' => 'pro']);
lookout_metrics()->distribution('page.load_ms', 42.5, ['route' => '/checkout'], MetricUnit::millisecond());
lookout_metrics()->flush();
```

### Real User Monitoring (browser)

[](#real-user-monitoring-browser)

Optional **Web Vitals** + **SPA / Livewire** navigation beacons: `POST /api/ingest/rum` (same project API key; **performance ingest** must be enabled on the project). Vanilla script with no npm dependencies:

- **`resources/rum/lookout-rum.js`** — `LookoutRum.init({ endpoint, apiKey, livewireNavigate: true, traceId: () => … })`. Puts **`api_key` in the JSON body** so **`navigator.sendBeacon`** works without custom headers. Correlate with server traces via **`trace_id`** (32 hex), e.g. from **`HtmlTraceMeta`** / a `` you render from `Tracer::instance()->traceId` on the server.

Error reporting client
----------------------

[](#error-reporting-client)

Uncaught exceptions use **`Lookout\Tracing\Reporting\ErrorReportClient`**: middleware enriches the payload (Laravel + HTTP context, git metadata, `context.attributes` from **`Lookout\Tracing\Reporting\ReportScope`** and configurable **`AttributeProviderInterface`** classes, optional **`client_solutions`** strings), then **`ReportTruncator`** enforces Lookout size limits, optional **`ReportSampler`** drops a random fraction, and the payload is POSTed immediately or **queued** and flushed on **shutdown** (`reporting.queue` / `reporting.send_immediately`).

### Glows (Flare-style manual breadcrumbs)

[](#glows-flare-style-manual-breadcrumbs)

Similar in spirit to [Flare Laravel glows](https://flareapp.io/docs/laravel/data-collection/glows): **custom timeline notes** that appear with other **breadcrumbs** on the error in Lookout (chronological “what ran before this failed”).

```
use Lookout\Tracing\GlowBreadcrumb;

GlowBreadcrumb::glow('Payment branch: validated wallet', 'info', ['wallet_id' => $id]);
GlowBreadcrumb::glow('Skipping cache (feature flag)', 'debug');
```

- **`$message`** — required; trimmed, max length enforced with other breadcrumbs.
- **`$level`** — string such as `debug`, `info`, `warning`, `error` (default `info`).
- **`$data`** — optional associative array (subject to the same redaction as other breadcrumb payloads).

Internally these are breadcrumbs with **`type`** `glow` and **`category`** `glow`. They are **not** the Spatie **`Flare::glow()`** API—there is no drop-in facade. They attach to the **error ingest** breadcrumb list, not as separate **span events** on traces (Flare also shows glows on spans in performance; Lookout’s buffer is scoped to the next error report).

### Manual filesystem breadcrumbs

[](#manual-filesystem-breadcrumbs)

For disk I/O there is no universal Laravel hook; use **`FilesystemBreadcrumb::record()`**:

```
use Lookout\Tracing\FilesystemBreadcrumb;

FilesystemBreadcrumb::record('read', '/var/app/config.json', 'info', ['bytes' => 1024]);
```

Optional **breadcrumb recorders** (same config block as core instrumentation, `instrumentation.enabled` must be true): **cache** hits/misses, **Redis** commands, **views** (view composer `*`), **outbound HTTP** (`Illuminate\Http\Client` events), **response** metadata (`ResponsePrepared`), **database transactions** (`TransactionBeginning` / `Committed` / `RolledBack`), **`dump()`** via Symfony VarDumper, plus manual **`Lookout\Tracing\GlowBreadcrumb::glow()`** and **`Lookout\Tracing\FilesystemBreadcrumb::record()`**. Env flags: `LOOKOUT_INSTRUMENT_CACHE`, `_REDIS`, `_VIEWS`, `_OUTBOUND_HTTP`, `_RESPONSE_DETAIL`, `_DATABASE_TRANSACTIONS`, `_DUMP`. Set **`LOOKOUT_INSTRUMENT_COMPREHENSIVE_COLLECTION=true`** to turn on the optional recorders above (plus SQL breadcrumbs and performance collectors for cache, Redis, views, log) in one step.

**Broad Laravel error context (what maps where)**

AreaLookoutApplication info`context.laravel`: framework + PHP version, **application name**, **locale**, **config cached**, **debug**, **application\_env** (`APP_ENV`), route/command/queue hintsLaravel contextSame `context.laravel` + **`context.log_context`** from `context()` / `Illuminate\Log\Context\Repository`Exception context**`context.exception_context`** when the throwable implements **`context()`** (redacted)Stacktrace argumentsStructured **`stack_frames[].args`** when `reporting.include_stack_arguments` is true and PHP supplies trace args (`zend.exception_ignore_args=0`)Requests / URL / user`url`, `user`, `issue_route`, `context.server`; HTTP breadcrumbsServer info`context.server` (hostname, SAPI, OS, pid, limits, tz) + request `SERVER_ADDR` when presentGit informationDefault **`GitInformationMiddleware`** (commit, etc.)Solutions**`SolutionsMiddleware`** + `reporting.client_solutions`Console commandsBreadcrumbs + performance spans when enabledJobs and queuesBreadcrumbs + queue trace propagation + performanceQueriesOptional SQL breadcrumbs; **DB spans** + query insights when performance DB collector onDatabase transactionsBreadcrumbs when `instrumentation.database_transactions` or `comprehensive_collection`Cache eventsBreadcrumbs + optional cache **spans**Redis commandsBreadcrumbs + optional Redis **spans**External HTTPBreadcrumbs + **http.client** spans (Guzzle / `Http::`)ViewsView composer breadcrumbs + optional view **spans**LogsOptional `MessageLogged` breadcrumbs; optional log **spans**; structured **`/api/ingest/log`** via `lookout_logger()`Livewire**`context.livewire`** (component class + name) on Livewire requestsSpans / errors when tracing**`LOOKOUT_PERFORMANCE_ENABLED`**, `Tracer::markTraceMustExport` on error reportsDumps`instrumentation.dump` → **`DumpInstrumentation`**Glows / filesystemManual **`GlowBreadcrumb::glow()`**, **`FilesystemBreadcrumb::record()`**Customise report**`reporting.middleware`**, **`AttributeProviderInterface`**, **`ReportScope`**Global no-op: `LOOKOUT_DISABLED` or `reporting.disabled`. Ingest fields **`is_log`**, **`open_frame_index`**, and **`grouping_override`** (custom fingerprint when `fingerprint` is empty; camelCase aliases **`isLog`**, **`openFrameIndex`**, **`overriddenGrouping`**) are stored on the server. In the Lookout app, **Project → Monitoring modes** can turn off **`POST /api/ingest/trace`** and **`POST /api/ingest/rum`** per project while leaving error ingest enabled.

### User feedback (crash page)

[](#user-feedback-crash-page)

Similar in spirit to [Sentry user feedback](https://docs.sentry.io/platforms/php/user-feedback/): when **`ErrorReportClient`** builds an error payload it ensures an **`occurrence_uuid`** (v4) and remembers it for **`lookout_last_error_occurrence_uuid()`** / **`ErrorReportClient::lastOccurrenceUuid()`**. On your custom error view, POST that UUID with the user’s message to **`POST /api/ingest/feedback`** (same project **`api_key`**; see Lookout **Ingest API → User feedback**). The comment appears on that occurrence’s thread in the app. Alternatively use the ingest response / read API **`event_id`** (ULID) as **`event_id`** in the feedback body.

Cron monitors (Sentry Crons–style)
----------------------------------

[](#cron-monitors-sentry-cronsstyle)

Aligned with [Sentry PHP Crons](https://docs.sentry.io/platforms/php/crons/): `in_progress` → `ok` / `error`, optional heartbeat, and monitor upsert via `monitor_config`.

```
use Lookout\Tracing\Cron\CheckInStatus;
use Lookout\Tracing\Cron\Client as CronClient;
use Lookout\Tracing\Cron\MonitorConfig;
use Lookout\Tracing\Cron\MonitorSchedule;

CronClient::configure([
    'api_key' => getenv('LOOKOUT_API_KEY'),
    'base_uri' => 'https://your-lookout-host.example',
    'cron_ingest_path' => '/api/ingest/cron',
]);

$config = MonitorConfig::make(MonitorSchedule::crontab('0 * * * *'), checkinMarginMinutes: 5);

$id = CronClient::captureCheckIn('hourly-job', CheckInStatus::inProgress(), monitorConfig: $config);
CronClient::captureCheckIn('hourly-job', CheckInStatus::ok(), $id);

CronClient::withMonitor('wrapped-job', fn () => doWork(), $config);

CronClient::captureCheckIn('heartbeat', CheckInStatus::ok(), null, 12.0);
```

Optional **`meta`** (string/number/bool values, size-limited server-side) on `captureCheckIn` attaches context to the check-in row and merges on completion.

Laravel: the same service provider configures `CronClient` from `config/lookout-tracing.php` (`cron_ingest_path` defaults to `/api/ingest/cron`).

Profiling (CPU / flame graphs)
------------------------------

[](#profiling-cpu--flame-graphs)

Aligned with [Sentry PHP profiling](https://docs.sentry.io/platforms/php/profiling/) in spirit: capture with **Excimer** (speedscope JSON), **xhprof** / **Tideways**, **SPX**, or cooperative **`php.manual_pulse`** sampling (no extension), then POST to Lookout.

```
use Lookout\Tracing\Profiling\ProfileClient;

ProfileClient::configure([
    'api_key' => getenv('LOOKOUT_API_KEY'),
    'base_uri' => 'https://your-lookout-host.example',
    'profile_ingest_path' => '/api/ingest/profile',
]);

ProfileClient::sendProfile([
    'agent' => 'other',
    'format' => 'speedscope',
    'data' => [/* speedscope JSON object */],
    'trace_id' => 'abc123…',
    'transaction' => 'GET /checkout',
]);
```

**First-party aggregate hotspots** (`lookout.v1`):

```
use Lookout\Tracing\Profiling\LookoutProfileV1Payload;
use Lookout\Tracing\Profiling\ProfileClient;

ProfileClient::sendProfile(LookoutProfileV1Payload::aggregateIngestBody(
    [
        ['file' => 'app/Services/Checkout.php', 'line' => 120, 'samples' => 48],
    ],
    meta: ['source' => 'custom-collector'],
    context: ['trace_id' => 'abc123…', 'transaction' => 'POST /checkout'],
));
```

Package classes under `Lookout\Tracing\Profiling\` (e.g. `ExcimerExporter`, `XhprofLikeExporter`, `SpxPayload`, `ManualPulseSampler`, `LookoutProfileV1Payload`) help build `agent` / `format` / `data` for each backend. Laravel: `LookoutTracingServiceProvider` merges the same `api_key`, `base_uri`, and `profile_ingest_path` from `config/lookout-tracing.php`.

**Overhead:** Lookout does not sample profiles for you — wrap `ProfileClient::sendProfile()` (or your Excimer/Tideways hooks) so production only uploads a small fraction of requests or when duration exceeds a threshold, similar to `profiles_sample_rate` / slow-transaction rules elsewhere.

Laravel
-------

[](#laravel)

Auto-discovery registers `Lookout\Tracing\Laravel\LookoutTracingServiceProvider`.

- Middleware alias: **`lookoutTracing.continueTrace`** — call `continueTrace()` from incoming headers.
- Publish config: `php artisan vendor:publish --tag=lookout-tracing-config`
- Env: `LOOKOUT_API_KEY`, `LOOKOUT_BASE_URI` (or `APP_URL`), optional `LOOKOUT_TRACING_AUTO_FLUSH=true`. Profile ingest path defaults to `/api/ingest/profile` (override in published config).

### Framework breadcrumbs &amp; exception reporting

[](#framework-breadcrumbs--exception-reporting)

The provider registers **event listeners** (when `instrumentation.enabled` is true) that append **breadcrumbs** for:

AreaLaravel events (indicative)HTTP`RouteMatched`, `RequestHandled`Console`CommandStarting`, `CommandFinished`Queue`JobProcessing`, `JobProcessed`, `JobFailed`, `JobExceptionOccurred`Optional`QueryExecuted` (sampled), `MessageLogged`, allowlisted domain events, or a wildcard listenerBreadcrumbs are **cleared** at each route match, Artisan command, or queue job so `queue:work` and Octane do not mix unrelated requests.

Set **`LOOKOUT_REPORT_EXCEPTIONS=true`** (plus API key and base URI) to register a **`reportable`** handler on the default exception handler. It POSTs to **`POST /api/ingest`** with:

- exception message, class, stack trace, and **stack frames**
- current **breadcrumbs**
- **trace** fields from `Tracer::errorIngestTraceFields()` when a transaction was started
- **`context.laravel`**: framework version, PHP version, route, queue job name, Artisan command, HTTP path/method when available

Tune knobs in `config/lookout-tracing.php` (`instrumentation.*`, `breadcrumbs_max`, `error_ingest_path`).

### Performance monitoring (traces &amp; spans)

[](#performance-monitoring-traces--spans)

Enable with **`LOOKOUT_PERFORMANCE_ENABLED=true`** (and keep `LOOKOUT_API_KEY` / `LOOKOUT_BASE_URI` set). This turns on **sampled span recording**: OpenTelemetry-style **trace ids**, **spans**, and optional **span events**, sent to **`POST /api/ingest/trace`** via `Tracer::flush()` or **`LOOKOUT_TRACING_AUTO_FLUSH=true`**. Ensure the project allows trace ingest in **Lookout → Project settings → Monitoring modes**; otherwise the API returns **403**.

1. **Middleware (order matters):** register **`lookoutTracing.continueTrace`** first, then **`lookoutTracing.performance`**, or set **`LOOKOUT_PERFORMANCE_AUTO_MIDDLEWARE=true`** to append only the performance middleware to `web` and `api` (you still add `continueTrace` yourself if it is not already in those groups).
2. **Sampling:** default **`RateSampler`** at **10%** (`LOOKOUT_PERFORMANCE_SAMPLE_RATE=0.1`). Implement `Lookout\Tracing\Performance\Sampler` and set `performance.sampler.class` for custom logic. Traces continued via `sentry-trace` with **`sampled=0`** never record spans (propagation only). Optional **tail sampling** (`LOOKOUT_PERFORMANCE_TAIL_SAMPLING=true`): keep slow roots (`LOOKOUT_PERFORMANCE_TAIL_SLOW_MS`), errors / 5xx, optional `LOOKOUT_PERFORMANCE_TAIL_RESIDUAL_RATE` for a thin random sample of the rest — same theme as lowering `traces_sample_rate` in production while still capturing outliers.
3. **Limits:** `performance.trace_limits` — max spans per export, max attributes per span / span event, max span events per span.
4. **Hooks:** `Tracing::configureSpans(fn (Span $span) => …)` and `Tracing::configureSpanEvents(fn (array $event) => …|null)` — return **`null`** from the span-event callback to drop an event.
5. **Collectors** (`performance.collectors.*`): HTTP server transaction, **database** queries (child `db.query` spans), **console** / **queue** root transactions, **log** lines as span events, and **HTTP client** spans when you attach **`GuzzleTraceMiddleware`** (see below).

CLI / queue: enable **`LOOKOUT_PERFORMANCE_FLUSH_CLI_QUEUE=true`** to flush after each command or job, or call **`Tracing::flush()`** yourself.

### Rails

[](#rails)

For Ruby on Rails, use the copy-paste module under **`packages/lookout-rails/`** in the Lookout repository (`lib/lookout_framework.rb` + README), or a git subtree mirror if you use `SPLIT_LOOKOUT_RAILS_REPO`: `ActiveSupport::Notifications` for controller and Active Job, optional SQL sampling, and `LookoutFramework.report_exception` from your error pipeline.

Guzzle 7
--------

[](#guzzle-7)

```
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Lookout\Tracing\Http\GuzzleTraceMiddleware;

$stack = HandlerStack::create();
$stack->push(GuzzleTraceMiddleware::create());

$client = new Client(['handler' => $stack]);
```

With **performance monitoring** enabled, the same middleware also records **`http.client`** child spans (when a parent span is active and sampling allows recording).

Requirements
------------

[](#requirements)

- PHP 8.3+
- `psr/http-message` (for the optional Guzzle middleware type hints)
- `guzzlehttp/guzzle` (optional, for `GuzzleTraceMiddleware` + promises)

SDK roadmap &amp; Lookout alignment
-----------------------------------

[](#sdk-roadmap--lookout-alignment)

The Lookout app surfaces **Traces**, **Transactions**, and **trace detail** in the web UI; the SDK sends **errors** (`POST /api/ingest`) and, when enabled, **spans** (`POST /api/ingest/trace`) with consistent **`trace_id`** / **`sentry-trace`** propagation.

Server behaviorSDK support**`performance_ingest_enabled`** falseTrace ingest returns **403**. Laravel: enable **`performance.sync_from_api`** (Sanctum token + project id) so **`Tracer::isPerformanceEnabled()`** matches the server on boot; or set **`LOOKOUT_PERFORMANCE_ENABLED=false`**. Auto-flush and queue/cli flush log **`lookout.tracing.trace_forbidden`** when **`performance.log_forbidden_trace_ingest`** is true (default).**`GET /api/v1/projects/{id}`****`LookoutManagementApi::fetchProject()`** + sync config (see `lookout-tracing.php` **`performance.sync_from_api`**).**429 / flaky network****`trace_ingest.max_attempts`**, **`retry_delay_ms`**, **`retry_statuses`** (env: **`LOOKOUT_TRACE_INGEST_*`**) — **`Tracer::flushWithResult()`** uses **`HttpTransport::postJsonWithResponseRetries()`**. **403** is never retried.### Implemented building blocks

[](#implemented-building-blocks)

- **`Lookout\Tracing\Interop\OpenTelemetryTraceConverter`** — OTLP JSON → Lookout: **`toJobPayloads()`** (one row set per `traceId`), **`toLookoutIngestBody()`** when only one trace is present, **`fromLookoutIngestBody()`** for OTLP export from native bodies. Lookout HTTP: **`POST /api/ingest/trace/otlp`** (same auth/gate as **`/api/ingest/trace`**).
- **`Lookout\Tracing\Http\ContinueTracePsr15Middleware`** — PSR-15 **`sentry-trace`** / **`baggage`** parsing (Slim, Mezzio, etc.).
- **`Lookout\Tracing\Support\DataRedactor::redact()`** — recursive redaction for span **`data`** / context-style arrays.
- **`Lookout\Tracing\Testing\TracerInspection::traceIngestBody()`** — stable access to **`buildTraceIngestBody()`** in tests.

### Still optional / app-specific

[](#still-optional--app-specific)

- Dedicated **OpenTelemetry PHP SDK** exporter package (protobuf / gRPC) — HTTP JSON ingest is covered by **`/api/ingest/trace/otlp`** and the converter.
- **PSR-15 “performance”** middleware (auto HTTP transactions) — today use manual **`Tracing::startTransaction`** or stay on Laravel.
- **Queue-based async flush** with deduplication across workers.

Scope
-----

[](#scope)

**Tracing** supports **manual** transactions/spans (`Tracing::trace()`, `startTransaction`) and optional **performance mode**: sampled **auto spans** for HTTP (middleware), SQL, Artisan, queue, logs, and outbound Guzzle calls, flushed to Lookout’s trace ingest.

**Framework instrumentation** (above) still records **breadcrumbs** for **error reports**; performance collectors add **span trees** for the distributed trace UI when you flush to **`/api/ingest/trace`**.

**Crons:** Lookout stores check-ins and monitor metadata; it does **not** yet auto-open issues or email you on missed schedules like Sentry’s hosted monitors—you can build alerting on top (e.g. scheduled jobs reading the API) or extend the app later.

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance60

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/3033e31411665568146bf823404e1d1c789fa0d93cba99ae3a891f100b4c279e?d=identicon)[tshafer](/maintainers/tshafer)

---

Top Contributors

[![tshafer](https://avatars.githubusercontent.com/u/299464?v=4)](https://github.com/tshafer "tshafer (8 commits)")

### Embed Badge

![Health badge](/badges/lookout-tracing/health.svg)

```
[![Health](https://phpackages.com/badges/lookout-tracing/health.svg)](https://phpackages.com/packages/lookout-tracing)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
