Skip to main content

APM

APM gives you per-transaction traces, a component breakdown (application versus database, cache, external), method-level spans, N+1 detection, and a CPU flamegraph. The target is WordPress (PHP) and .NET. The client installs nothing: the agent provisions everything it needs, and it never restarts your services on its own.

APM comes in three depths. You can run any subset.

Layer 1: RED metrics, zero touch

Request rate, errors and duration at the protocol level, with no reload of your web server or app. On a full kernel this uses eBPF to observe HTTP request and reply timing on watched ports, plus the client-side round trip to the database and cache, giving you a component breakdown (which fraction of the request waited on the DB). Where eBPF is not available (an unprivileged container), the same RED numbers are sourced from the access log instead. Nothing to install, no restart.

Layer 2: method-level spans

The Site24x7-grade trace tree (request, then WP hooks, then the SQL query). This uses the OpenTelemetry PHP extension or the .NET CLR profiler. The agent fingerprints the runtime (PHP version, thread safety, architecture, libc), pulls the exact signed prebuilt artifact from the release channel, validates it aside, and then stages the change. A human applies the reload when it suits them. The agent writes the change and reports it, it does not touch php-fpm or the app pool itself. See Never restart your services.

Spans flow to the agent's local OTLP receiver (see Local ingest ports) and up the WebSocket to storage, where they become a waterfall. The receiver speaks standard OTLP, so it also accepts spans from any other OpenTelemetry SDK (Java, Node, Python, Go), not just the PHP and .NET runtimes the agent provisions.

Layer 3: CPU flamegraph

A sampling profiler that reads the live stack from outside the process, with no extension and no reload. For PHP it reads the php-fpm VM stack directly. For .NET it uses the runtime's built-in EventPipe through a provisioned dotnet-trace, folds the samples by self-time, and produces the same flamegraph. This needs only a ptrace capability, a Speed-2 grant, and it opens up the "main" time that request-level tools cannot see.

WordPress-aware

The layer-3 profiler attributes CPU to the responsible plugin, theme, or core, by reading each frame's file path. You see "which plugin burns CPU" as owner_pct per plugin.

Planned

Layer-2 span enrichment that attributes each span to the plugin behind the callback (sampled deep-trace) is designed but not built yet. The layer-3 CPU attribution above is live.

N+1 and external-wait

The server detects N+1 query patterns in the span data (many repeated normalized queries in one trace) and raises an insight. The layer-1 component tracking also watches outbound calls so "the page is waiting on a third-party API" shows up alongside the database time.

Where it works

Layers 2 and 3 work inside an LXC container (same PID namespace). Only layer 1's eBPF path needs kernel privilege, so in an unprivileged container layer 1 falls back to access-log RED while spans and the flamegraph still work. Container APM is covered by the agent reading sibling container stacks by host PID plus the app exporting OTLP to the bridge gateway.

Planned

arm64 prebuilt APM artifacts and a ZTS (thread-safe) PHP profiler variant are planned. The amd64 matrix and the standard non-thread-safe php-fpm case are live.