Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Riemann Client Php Laravel Package

trademachines/riemann-client-php

A PHP client for Riemann, the event stream processor for monitoring distributed systems. Send events, metrics, and state updates from your Laravel or PHP applications to a Riemann server with a simple, expressive API.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm the shape of the API first. This is a thin, low-traffic package (0 dependents), so treat the repository itself as the documentation of record:

composer require trademachines/riemann-client-php

Before writing any integration code, open these in order:

  1. README.md — install snippet and the canonical "send one event" example.
  2. src/ — find the client entry point (typically a Client class with send() / sendEvents()).
  3. The generated Protocol Buffers classes (usually under src/Proto/ or similar) — this tells you exactly which Event fields exist (host, service, state, metric, description, tags, ttl, attributes, time) and their types.
  4. composer.json — PHP version constraint and whether ext-protobuf is required or whether the messages are pure-PHP generated classes. This determines your deploy image.

Riemann speaks Protocol Buffers over a raw TCP socket (default port 5555), so your first smoke test needs a reachable Riemann instance — locally that is usually docker run -p 5555:5555 -p 4567:4567 riemann/riemann.

First use case: emit a single event and see it land. Start with one event rather than a metrics pipeline, because the fastest way to validate the whole chain (socket → protobuf → Riemann index) is to look at the event in Riemann's dashboard or query it from the CLI:

$client = new \Riemann\Client('127.0.0.1', 5555);

$event = new \Riemann\Proto\Event();
$event->setHost(gethostname());
$event->setService('myapp.heartbeat');
$event->setState('ok');
$event->setMetric(1.0);
$event->setTtl(60.0);

$client->send($event);

Confirm it arrived before building anything on top:

riemann-client query 'service = "myapp.heartbeat"'
# or open http://localhost:4567 in riemann-dash

Note: construct-then-set (or a fluent builder, if the package provides one) is the usual idiom here. Adapt the exact class names to what src/ actually exposes — the pattern is stable across Riemann clients, the namespace is not.

Implementation Patterns

Wrap the client in one small service, never call it from controllers. The client is stateful (a socket) and monitoring failures must never break a request. Bind a single wrapper in the container so connection setup, error swallowing, and default fields live in one place:

final class RiemannReporter
{
    public function __construct(private \Riemann\Client $client) {}

    public function gauge(string $service, float|int $value, array $tags = [], ?float $ttl = null): void
    {
        try {
            $event = new \Riemann\Proto\Event();
            $event->setHost(gethostname());
            $event->setService($service);
            $event->setMetric((float) $value);
            $event->setTtl($ttl ?? 60.0);
            $event->setState('ok');
            $event->setTags($tags);
            $this->client->send($event);
        } catch (\Throwable $e) {
            report($e); // never rethrow into the request path
        }
    }
}

Define a naming convention before the first event ships. service is the primary key in Riemann; host + service is the identity of an event stream. Pick {app}.{component}.{measurement} (e.g. shop.checkout.queue_depth) and document it. Renaming a service later orphans history and silently breaks any dashboard or alert bound to the old name.

Send batches from scheduled collectors, single events from request paths. If you sample N metrics in an Artisan command, build all the Event objects first and send them in one sendEvents() call — one socket round trip instead of N. From inside a web request or queue worker, send at most one or two events and make it non-blocking (see Gotchas).

Use attributes for anything high-cardinality, tags for anything you filter on. Attributes are a free-form map and are the right home for tenant IDs, queue names, or build numbers. Tags are effectively a set you query with tagged "...". Never fold a dimension into the service string unless you want a separate alerting entity for it.

Adopt the conventional state vocabulary. Riemann itself does not enforce states, but every dashboard and every alert rule you will write assumes them: ok, warning, critical, and expired (which Riemann assigns itself — never send it). Reserve state for health; put the actual number in metric.

Drive it from the scheduler with a TTL longer than the interval. The canonical pattern is a metrics:collect command on a everyMinute() schedule, sending events with ttl of 90–120s. The TTL is what makes Riemann useful: if your cron dies, the event expires and you get alerted without writing a single "no data" rule.

Test against a real Riemann, but isolate the client. For unit tests, put an interface in front of the reporter (or inject a fake client) so tests assert on the events you would send — inspect the built Event objects rather than asserting on socket behaviour. For one integration test, run Riemann in Docker in CI and assert with a query.

Gotchas and Tips

  • Riemann is fire-and-forget over TCP. A successful send() means the bytes reached the socket, not that Riemann indexed them. Do not use the absence of an exception as proof of delivery, and never use Riemann itself as the source of truth for an alerting path you need to be reliable.
  • Blocking sockets will bite you in the request path. A default PHP stream/socket has no meaningful timeout; if the Riemann host is unreachable-but-routable you can hang a request for the OS TCP timeout. Set an explicit connect/read timeout on the client if the package exposes one, and otherwise keep Riemann emission out of synchronous HTTP requests entirely.
  • The server closes idle connections. Long-lived processes (queue workers, daemons) that hold one client for hours will eventually hit a dead socket. Either reconnect per batch or wrap send() in a retry-once-after-reconnect.
  • ttl is a contract, not a decoration. Setting ttl shorter than your send interval produces a permanent expired flap that will page you at 3am. Setting it to 0/unset means the event never expires, so a dead collector looks healthy forever. Match TTL to ~1.5–2× the interval.
  • metric nil vs 0. Protobuf optional fields distinguish "not set" from zero. If you cast carelessly ((float) null), you turn a "no measurement" into a fake zero and corrupt your graphs. Decide explicitly per service whether a missing value should suppress the event or send a state-only event.
  • Regenerating protobuf classes is not something you should do casually. The checked-in generated classes are the contract. If you need a field the package doesn't expose, prefer attributes over forking and regenerating.
  • Check whether UDP is supported. Riemann accepts UDP on 5555 too; it is lossy but non-blocking. For high-frequency, low-value metrics from a web tier, UDP is sometimes the right trade — just don't put anything alert-critical on it.
  • Debug at the wire, not in PHP. nc -v localhost 5555 proves reachability, and tcpdump -i lo port 5555 proves you're actually sending. Most "the client is broken" reports are a firewall rule or a container-network mismatch.
  • Extension points are minimal, so design around them. With a thin, low-maintenance package like this, plan on decorating rather than extending: your RiemannReporter wrapper is where you add default host, batching, sampling, sanitisation, and a null-object implementation for local dev. That keeps the direct dependency surface to one file.
  • Pin the version and budget for abandonment. Zero dependents and a single vendor mean no community safety net. Pin exactly in composer.json, and make sure your wrapper is small enough that swapping the underlying transport (or shelling out to riemann-client) is a one-file change.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel