Streams and observability
Metrics, cloud events, streams, subscriptions to external sinks, and alert rules.
Data sources#
| Source | Client | Content |
|---|---|---|
| Metrics | fabric.metrics() | Time series per connection, port or metro: bandwidth in and out, packets, errors, inter-metro latency |
| Cloud events | fabric.cloudEvents() | State changes and alerts in CloudEvents format |
| Streams | fabric.streams(), streamAssets(), streamSubscriptions(), streamAlertRules() | A push pipeline: assets attached to a stream emit metrics and events, subscriptions deliver them to a sink |
/fabric/v4/streams returned 403 for the account used in live validation on 2026-11-11, so the stream calls on this page were verified against the specification and with WireMock only.
Metrics#
The metrics API replaces the statistics endpoints of earlier releases. A query names its subject through MetricQuery or through one of the per-asset methods.
import com.eqixiac.equinix.fabric.model.Metric;
import com.eqixiac.equinix.fabric.model.implementation.filter.MetricQuery;
LocalDateTime to = LocalDateTime.now(ZoneOffset.UTC);
LocalDateTime from = to.minusHours(24);
List<Metric> series = fabric.metrics().forConnection(connectionUuid, from, to,
"equinix.fabric.connection.bandwidth_rx.usage", "equinix.fabric.connection.bandwidth_tx.usage");
for (Metric metric : series) {
System.out.println(metric.getName() + " [" + metric.getUnit() + "] every " + metric.getInterval()
+ ", " + metric.getDatapoints().size() + " points");
}
fabric.metrics().search(MetricQuery.forPort(portUuid)
.names("equinix.fabric.port.bandwidth_rx.usage")
.between(from, to)
.interval("PT1H"));forPort(...) and forMetro(...) have the same shape as forConnection(...). The metric names in the block follow the naming pattern of the Fabric observability catalogue and were not checked against it for each asset type.
The live service showed two constraints on 2026-11-11.
- It rejects a metric search that has no subject, project or organization filter.
MetricQuerysets the subject on every query. GET /{asset}/{id}/metricsrejects alimitparameter with HTTP 400EQ-3045002, so the SDK sends nolimiton that call.
The live port-metrics response sends summary as an object where the specification types a string. Metric.getSummary() returns the JSON text of that object, and getSummaryNode() returns the node.
Cloud events#
import com.eqixiac.equinix.fabric.model.CloudEvent;
import com.eqixiac.equinix.fabric.model.implementation.filter.CloudEventQuery;
for (CloudEvent event : fabric.cloudEvents().search(
CloudEventQuery.forAsset("connections", connectionUuid)
.after(LocalDateTime.now(ZoneOffset.UTC).minusDays(7)))) {
System.out.println(event.getTime() + " " + event.getType() + " " + event.getSeverityText()
+ " " + event.getSubject());
}
fabric.cloudEvents().search(CloudEventQuery.forProject(projectId).types("equinix.fabric.connection.state.down"));CloudEventQuery.forSubjects(...), forProject(...) and forOrganization(...) build the filter that the service requires. searchLiveEvents(...) queries the live-events endpoint. Whether that endpoint is the active-alerts API is listed as unverified in the review of 2026-11-11.
Streams#
A stream is a named channel in a project. Assets attached to the stream emit metrics and events into it, and each subscription delivers them to one sink.
import com.eqixiac.equinix.fabric.enums.StreamType;
import com.eqixiac.equinix.fabric.model.Stream;
Stream stream = fabric.streams().define()
.withType(StreamType.TELEMETRY_STREAM)
.withName("prod-interconnect-telemetry")
.withDescription("Connections, ports and Cloud Routers of project prod")
.create();
// asset kind as in the path /fabric/v4/streams/{streamId}/{asset}/{assetId}
fabric.streamAssets().attach(stream.getUuid(), "connections", connectionUuid, true); // true = metrics enabled
fabric.streamAssets().attach(stream.getUuid(), "ports", portUuid, true);
fabric.streamAssets().attach(stream.getUuid(), "routers", routerUuid, true);Subscriptions#
The sink types are DATADOG, DYNATRACE, GOOGLE_PUBSUB, PAGERDUTY, SERVICENOW, SLACK, SPLUNK_HEC, TEAMS and WEBHOOK.
import com.eqixiac.equinix.fabric.enums.StreamSubscriptionSinkCredentialType;
import com.eqixiac.equinix.fabric.enums.StreamSubscriptionSinkType;
import com.eqixiac.equinix.fabric.enums.StreamSubscriptionType;
import com.eqixiac.equinix.fabric.model.StreamSubscription;
StreamSubscription toSplunk = fabric.streamSubscriptions().define(streamUuid)
.withType(StreamSubscriptionType.STREAM_SUBSCRIPTION)
.withName("splunk-hec-prod")
.withEnabled(true)
.withSinkType(StreamSubscriptionSinkType.SPLUNK_HEC)
.withSinkUri("https://splunk.example.com:8088/services/collector")
.withCredentialType(StreamSubscriptionSinkCredentialType.ACCESS_TOKEN)
.withAccessToken(System.getenv("SPLUNK_HEC_TOKEN"))
.withBatchEnabled(true)
.withBatchSizeMax(50)
.withBatchWaitTimeMax(5)
.create();withMetricSelector(...) and withEventSelector(...) restrict what a subscription delivers. Equinix stores the sink credential, so the credential should permit writing to that one destination and nothing else.
Alert rules#
An alert rule evaluates a metric on the stream's assets and emits an alert event that subscriptions deliver.
import com.eqixiac.equinix.fabric.enums.StreamAlertRuleType;
fabric.streamAlertRules().define(streamUuid)
.type(StreamAlertRuleType.METRIC_ALERT)
.name("connection-rx-above-80-percent")
.enabled(true)
.metricSelector(Map.of("include", List.of("equinix.fabric.connection.bandwidth_rx.usage")))
.resourceSelector(Map.of("include", List.of("*/connections/" + connectionUuid)))
.detectionMethod(Map.of(
"type", "THRESHOLD",
"operand", "ABOVE",
"windowSize", "PT15M",
"warningThreshold", "700000000",
"criticalThreshold", "800000000"))
.create();The three selector arguments are maps that the SDK serializes as given. Their keys follow the metricSelector, resourceSelector and detectionMethod schemas of the Fabric specification, and the values above illustrate that shape and were not tested against the service. In 4.0 the SDK sends an alert-rule update as PUT, where release 3.0.0 sent PATCH, which the specification does not define on that path.
Pull or push#
| Need | Use | Reason |
|---|---|---|
| A report or a capacity review | metrics() pull | No standing infrastructure; bounded by the retention of the metrics API |
| Dashboards and alerting in an existing tool | Stream with a subscription | Equinix pushes; nothing to poll, no rate-limit exposure |
| Audit of state changes | cloudEvents() search, or an event selector on a subscription | Events carry the actor (authId) and a trace context |
The observability walkthrough builds the push pipeline end to end.