Skip to content

Stream health and test delivery

Stream health and test delivery

Two kinds of failure

Kind Examples What the pump does
transient timeout, connection refused, 408, 429, 5xx bounded exponential backoff per row, dead-letter at the cap; the breaker opens after failure_threshold consecutive failures
authentication / configuration 401/403, a bad signature, a revoked key, a refused token exchange, no such bucket, wrong region the breaker opens at once; the rows stay pending and their attempts are not incremented

A sink signals the second kind by throwing Cbox\LaravelSiem\Exceptions\DestinationRefused (a StreamDeliveryFailed subclass carrying a FailureKind). Every built-in sink maps responses this way, including the HTTP collectors (a 401/403 from Splunk or Elastic is a refusal too).

Why: retrying a refused key cannot succeed, and burning the retry budget would dead-letter audit events because of a credential problem. Instead the stream probes once per circuit_breaker.cooldown_seconds until it is fixed, and the outbox bound (backpressure.max_pending) still caps how much can pile up.

The status

Every failure records last_error (scrubbed), last_failure_kind and last_failure_at on the stream; a success clears them. $stream->health() (or CircuitBreaker::health($stream)) answers:

Health Meaning
healthy the last attempt succeeded
degraded transient failures, still retrying
paused the breaker is open after repeated transient failures; resumes on its own
action_required the destination refused the credentials or configuration; an operator must fix it

Updating a stream's secret, options, endpoint_url or destination through LogStreams::update() re-validates the settings and resets the breaker, so the next pump delivers straight away.

Test delivery

use Cbox\LaravelSiem\Contracts\StreamTester;

$result = app(StreamTester::class)->test($stream);

$result->delivered;  // bool
$result->failure;    // FailureKind|null
$result->error;      // scrubbed message, for the operator
$result->eventId;    // the marker event's id (siem-test-…)

The tester formats one marker event (action siem.stream.test, a message saying it is safe to ignore) with the stream's formatter and redaction and sends it through the bound sink — same target, SSRF guard and credentials as the pump — synchronously and outside the outbox. A success also closes the breaker and clears action_required; a failure changes nothing on the stream.