PHP collector
Use seamward/php-collector when you are building a framework adapter or need direct control over observation and delivery in a PHP application. Laravel applications should normally use the Laravel collector, which includes this core package.
Status
The PHP collector is in alpha and is available from Packagist as 0.1.0-alpha.1.
Install
Install the framework-neutral package with:
Code example
composer require seamward/php-collector:^0.1@alphaChoose a transport
The core does not depend on Laravel, Symfony, Guzzle, or a specific HTTP client. Implement the small Transport interface with the HTTP client your application already uses:
Code example
use Seamward\Collector\Shipping\ShippingRequest;use Seamward\Collector\Shipping\ShippingResponse;use Seamward\Collector\Transport\Transport;
final class AppTransport implements Transport{ public function send(ShippingRequest $request): ShippingResponse { $response = $this->http->post( $request->endpoint, $request->body, $request->headers, );
return new ShippingResponse($response->status(), $response->body()); }}ShippingRequest already contains the exact signed body and required headers. The transport should return the status and response body without applying its own retry policy.
Record an observation
Code example
use Seamward\Collector\Collector;use Seamward\Collector\Configuration\Connection;use Seamward\Collector\Observation\Observation;use Seamward\Collector\Observation\Operation;
$collector = Collector::connect( connection: Connection::fromCredentials($connectionKey, $ingestToken), transport: new AppTransport($http),);
$collector->record(new Observation( operation: Operation::outboundHttp('POST', '/v1/candidates'), statusCode: 201, durationMs: 48, payload: (object) ['id' => 'local-value'],));Payload values are used only to build a structural shape and fingerprint. The envelope has no field for raw bodies or headers. Correlation identifiers and business object ids are keyed hashes before they enter the buffer.
Every completed PHP envelope is checked against the strict envelope 0.2 contract before it enters the buffer. Invalid metadata increments buildErrors and never escapes into the host application. The shared conformance corpus verifies the same valid and invalid cases against the Node.js contract schema.
Observe a queue
Wrap the broker call and use a stable queue, topic, or subscription label. The callback result and exception remain authoritative:
Code example
$published = $collector->observeQueuePublish( queueName: 'candidate-events', message: $message, publisher: fn ($message) => $queue->publish('candidate-events', $message), eventType: 'candidate.published',);
$handled = $collector->observeQueueConsumer( queueName: 'candidate-events', message: $message, consumer: fn ($message) => $handler->handle($message),);Queue success projects to status 202, an explicit disposition: "rejected" result projects to 422, and a thrown host exception projects to 500 before it is rethrown. These values describe evidence only. The collector never acknowledges, retries, or dead-letters a broker message.
Observe a scheduled feed
Wrap one import or export run. Use inbound for imports and outbound for exports:
Code example
$result = $collector->observeScheduledFeed( feedName: 'nightly-candidate-import', direction: 'inbound', payload: $rows, handler: fn ($rows) => $importer->import($rows),);A completed feed projects to status 200, an explicit rejection to 422, and a thrown host exception to 500.
Add deployment context
Pass stable release metadata to Collector::connect():
Code example
$collector = Collector::connect( connection: Connection::fromCredentials($connectionKey, $ingestToken), transport: new AppTransport($http), deployment: [ 'service' => 'candidate-api', 'release' => $release, 'commitSha' => $commitSha, ],);Explicit values win. Otherwise, the core recognizes SEAMWARD_SERVICE, SEAMWARD_RELEASE, SEAMWARD_COMMIT_SHA, VERCEL_GIT_COMMIT_SHA, RENDER_GIT_COMMIT, RAILWAY_GIT_COMMIT_SHA, and GITHUB_SHA. Invalid values are ignored. A valid Observation::$deployment value overrides the collector default for that one observation.
Delivery and failure behavior
Call $collector->flush() at a safe lifecycle boundary. The PHP core deliberately has no timer, destructor network call, or stop() method. Delivery failures never throw into the host application. Retryable batches remain in a bounded in-memory queue, non-retryable 4xx results are counted as rejected, mixed 207 results are accounted for per envelope, and overflow drops the oldest evidence.
Use $collector->stats() to read enqueued, shipped, rejected, dropped, failedBatches, queueLength, and buildErrors.
