onematrix/tracing-sdk
A lightweight tracing SDK for Laravel and PHP applications. Instrument requests, jobs, and custom spans to capture timing and context, then export traces to your observability backend. Simple APIs help you add distributed tracing without heavy dependencies.
Install and publish the config first — the defaults are almost certainly pointed at a demo indexer, not yours:
composer require onematrix/tracing-sdk
php artisan vendor:publish --tag="tracing-sdk-config"
Set the indexer endpoint and credentials in .env (namespacing may differ; check config/tracing-sdk.php after publishing):
TRACING_INDEXER_URL=https://indexer.internal
TRACING_INDEXER_TOKEN=your-service-token
TRACING_CANONICALIZER=json # json (RFC 8785) | xml (W3C C14N)
TRACING_HASH=keccak-256
The core primitive is: canonicalize → hash → ship. A first end-to-end use case is stamping an audit record for a domain object and letting the indexer hold the integrity proof:
use OneMatrix\Tracing\Tracing;
$record = Tracing::json($invoice->toAuditArray()) // RFC 8785 JCS bytes
->hash() // Keccak-256 over those bytes
->withMeta(['type' => 'invoice', 'id' => $invoice->id]);
$record->canonical(); // exact bytes that were hashed — store this
$record->digest(); // 64-char hex, Keccak-256
Tracing::send($record); // POST to the indexer
Read, in order: the config file, the canonicalizer classes (JSON JCS vs XML C14N), the hasher, and how the HTTP client is bound in the service provider — that last binding is where you redirect it to a staging indexer or a fake in tests.
Hash once, persist the canonical bytes. Store canonical() next to digest() in your own table. Verification later becomes a byte comparison instead of re-canonicalizing a record that may have drifted. If you only keep the digest, you can never reproduce the proof after a schema or serializer change.
Emit from Eloquent observers, send from a queued job. Hashing is cheap; the HTTP call is not. Keep the observer synchronous (it captures the canonical snapshot at write time) and dispatch the send:
class InvoiceObserver
{
public function updated(Invoice $invoice): void
{
$record = Tracing::json($invoice->auditablePayload())->hash();
IntegrityRecord::create([
'subject_type' => $invoice::class,
'subject_id' => $invoice->id,
'canonical' => $record->canonical(),
'digest' => $record->digest(),
]);
SendToIndexer::dispatch($record)->onQueue('tracing');
}
}
Wrap the SDK behind your own interface. With zero stars and zero dependents, treat the package as an implementation detail. A small IntegrityService contract lets you swap the library, point tests at a stub, or fall back to hash_hmac if the indexer is unreachable:
interface IntegrityService {
public function stamp(array|string $payload, array $meta = []): IntegrityRecord;
public function verify(IntegrityRecord $record): bool;
}
Test with Http::fake(). Because the transport is over HTTP, you get normal Laravel testing ergonomics — assert the outbound payload shape without a live indexer:
Http::fake(['indexer.internal/*' => Http::response(['accepted' => true], 202)]);
Use the XML path for document payloads, not for arrays you happen to serialize to XML. W3C C14N exists to match signatures produced by other systems (UBL, SAML, SOAP). If both ends are yours, JCS JSON is simpler and less namespace-sensitive.
Batch deliberately. If the SDK exposes a batch send, prefer it for backfills — but keep event-driven sends one-per-record so a single failure doesn't poison an entire batch.
0x-prefixed 64 hex chars) and not hash('sha3-256', ...).-0, shortest round-trip floats, specific exponent thresholds. PHP's json_encode differs at the edges. Do not hand-roll canonicalization with json_encode($x, JSON_UNESCAPED_SLASHES) and expect interoperability — verify against the RFC test vectors and pin a version.strcmp. Mixed emoji/ASCII keys expose the difference. Again: vectors, not intuition.BLOB, not TEXT — collation and charset conversion will bite you). Verify by re-hashing the stored bytes.Http::retry(...) with backoff rather than a naive loop.php artisan config:cache will freeze your .env values. Obvious, but this class of package is often wired up mid-deploy and then "mysteriously" points at staging.How can I help you explore Laravel packages today?