Ingest Guide
Ruptura accepts telemetry from three sources: Prometheus remote_write, OTLP over HTTP, and DogStatsD UDP. All three feed the same analysis pipeline — you can mix them freely from different workloads.
Quick reference
| Source | Protocol | Port | Path |
|---|---|---|---|
| Prometheus remote_write | HTTP POST (protobuf) | 8080 | /api/v2/write |
| OTLP metrics | HTTP POST (JSON) | 4317 | /otlp/v1/metrics |
| OTLP logs | HTTP POST (JSON) | 4317 | /otlp/v1/logs |
| OTLP traces | HTTP POST (JSON) | 4317 | /otlp/v1/traces |
| DogStatsD | UDP | 8125 | — |
| Loki push | HTTP POST (JSON) | 4317 | /loki/api/v1/push |
| Elasticsearch bulk | HTTP POST (JSON) | 4317 | /_bulk |
!!! important "OTLP format"
Ruptura's OTLP endpoint accepts JSON encoding only (no protobuf) and no compression (no gzip). Always configure exporters with encoding: json, compression: none.
1. Prometheus remote_write
The simplest path for Kubernetes clusters that already run Prometheus.
# prometheus.yml
global:
scrape_interval: 15s
remote_write:
- url: http://ruptura.ruptura-system.svc.cluster.local:80/api/v2/write
authorization:
type: Bearer
credentials: <your-api-key>
queue_config:
max_samples_per_send: 1000
batch_send_deadline: 5s
Ruptura reads standard Kubernetes labels (namespace, pod, deployment) from the metric labels and maps them to workload identities automatically.
2. OpenTelemetry Collector
The recommended path for production — the OTel Collector handles buffering, retry, and fan-out.
Full pipeline (metrics + logs + traces)
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc: {endpoint: 0.0.0.0:4317}
http: {endpoint: 0.0.0.0:4318}
prometheus:
config:
scrape_configs:
- job_name: k8s
kubernetes_sd_configs:
- role: pod
processors:
batch:
timeout: 5s
k8sattributes:
extract:
metadata: [k8s.namespace.name, k8s.deployment.name, k8s.pod.name]
exporters:
otlphttp/ruptura:
endpoint: http://ruptura.ruptura-system.svc.cluster.local:4317
encoding: json # required — Ruptura does not accept protobuf
compression: none # required — Ruptura does not accept gzip
headers:
Authorization: "Bearer <your-api-key>"
service:
pipelines:
metrics:
receivers: [prometheus, otlp]
processors: [k8sattributes, batch]
exporters: [otlphttp/ruptura]
logs:
receivers: [otlp]
processors: [k8sattributes, batch]
exporters: [otlphttp/ruptura]
traces:
receivers: [otlp]
processors: [k8sattributes, batch]
exporters: [otlphttp/ruptura]
Resource attributes Ruptura reads
Ruptura uses these OTLP resource attributes to group telemetry into workloads:
| Attribute | Used for |
|---|---|
k8s.namespace.name |
Namespace (required for workload identity) |
k8s.deployment.name |
Maps to Deployment workload |
k8s.statefulset.name |
Maps to StatefulSet workload |
k8s.daemonset.name |
Maps to DaemonSet workload |
k8s.job.name |
Maps to Job workload |
service.name |
Fallback workload name when no k8s.* present |
host.name |
Node-level identity |
Multiple pods from the same Deployment are automatically merged into a single health view.
3. Direct OTLP/HTTP (curl / scripts)
You can send OTLP JSON directly with curl — useful for testing, CI pipelines, or custom ingest scripts.
Metrics
T=$(date +%s%N)
curl -X POST http://<host>:4317/otlp/v1/metrics \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <api-key>" \
-d '{
"resourceMetrics": [{
"resource": {"attributes": [
{"key": "service.name", "value": {"stringValue": "payment-api"}},
{"key": "k8s.namespace.name", "value": {"stringValue": "production"}}
]},
"scopeMetrics": [{"metrics": [
{
"name": "process.cpu.utilization",
"gauge": {"dataPoints": [{
"timeUnixNano": "'$T'",
"asDouble": 0.85
}]}
},
{
"name": "process.memory.utilization",
"gauge": {"dataPoints": [{
"timeUnixNano": "'$T'",
"asDouble": 0.72
}]}
},
{
"name": "http.server.request.duration",
"gauge": {"dataPoints": [{
"timeUnixNano": "'$T'",
"asDouble": 1240
}]}
},
{
"name": "http.server.error.rate",
"gauge": {"dataPoints": [{
"timeUnixNano": "'$T'",
"asDouble": 0.42
}]}
}
]}]
}]
}'
Metric names that influence KPI signals:
| Metric name | Signal affected |
|---|---|
process.cpu.utilization |
stress, pressure |
process.memory.utilization |
fatigue, pressure |
http.server.request.duration |
velocity, stress |
http.server.error.rate |
mood, resilience |
runtime.gc.pause.duration |
fatigue |
process.open_file_descriptors |
entropy |
| Any gauge metric | General signal input |
Logs
T=$(date +%s%N)
curl -X POST http://<host>:4317/otlp/v1/logs \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <api-key>" \
-d '{
"resourceLogs": [{
"resource": {"attributes": [
{"key": "service.name", "value": {"stringValue": "payment-api"}},
{"key": "k8s.namespace.name", "value": {"stringValue": "production"}}
]},
"scopeLogs": [{"logRecords": [
{
"timeUnixNano": "'$T'",
"severityNumber": 9,
"severityText": "INFO",
"body": {"stringValue": "Payment tx_9921 authorized, latency=340ms"}
},
{
"timeUnixNano": "'$((T+200000000))'",
"severityNumber": 17,
"severityText": "ERROR",
"body": {"stringValue": "DB connection pool exhausted: 20/20 active"},
"attributes": [
{"key": "db.pool.active", "value": {"intValue": 20}},
{"key": "error.type", "value": {"stringValue": "PoolExhausted"}}
]
},
{
"timeUnixNano": "'$((T+400000000))'",
"severityNumber": 21,
"severityText": "FATAL",
"body": {"stringValue": "Circuit breaker OPEN — rejecting all requests"},
"attributes": [
{"key": "cb.state", "value": {"stringValue": "open"}}
]
}
]}]
}]
}'
OTLP severity numbers:
| Range | Level | Effect |
|---|---|---|
| 1–4 | TRACE | ignored |
| 5–8 | DEBUG | ignored |
| 9–12 | INFO | positive signal (+mood) |
| 13–16 | WARN | negative signal (−mood) |
| 17–24 | ERROR / FATAL | strong negative signal (−mood, −resilience) |
JSON value types:
Use {"stringValue": "..."} for strings, {"intValue": 42} (JSON number) for integers, {"boolValue": true} for booleans. Do not quote integers — {"intValue": "42"} is invalid.
Traces
T=$(date +%s%N)
TRACE_ID=$(cat /proc/sys/kernel/random/uuid | tr -d '-') # 32 hex chars
SPAN_ID=$(cat /proc/sys/kernel/random/uuid | tr -d '-' | cut -c1-16) # 16 hex chars
curl -X POST http://<host>:4317/otlp/v1/traces \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <api-key>" \
-d '{
"resourceSpans": [{
"resource": {"attributes": [
{"key": "service.name", "value": {"stringValue": "order-service"}},
{"key": "k8s.namespace.name", "value": {"stringValue": "production"}}
]},
"scopeSpans": [{"spans": [
{
"traceId": "'$TRACE_ID'",
"spanId": "'$SPAN_ID'",
"name": "POST /orders",
"kind": 2,
"startTimeUnixNano": "'$T'",
"endTimeUnixNano": "'$((T+320000000))'",
"status": {"code": 1},
"attributes": [
{"key": "http.method", "value": {"stringValue": "POST"}},
{"key": "http.status_code", "value": {"intValue": 201}}
]
}
]}]
}]
}'
Span status codes:
| Code | Meaning | Effect on FusedR |
|---|---|---|
| 0 | UNSET | neutral |
| 1 | OK | positive |
| 2 | ERROR | traceR += (error_rate × 5.0) → raises FusedR |
Ruptura tracks error rate per service in a sliding window. When ≥10 spans have arrived or 15 seconds have passed, the window flushes and traceR is computed as 0.6×errorRate + 0.4×(avgLatencyMS/200). This feeds directly into the Fused Rupture Index.
4. DogStatsD
Ruptura listens for DogStatsD metrics on UDP port 8125 (same format as Datadog Agent).
# Python — datadog library
from datadog import initialize, statsd
initialize(statsd_host='<ruptura-host>', statsd_port=8125)
statsd.gauge('payment.latency_ms', 1240, tags=['service:payment-api', 'namespace:production'])
statsd.gauge('payment.error_rate', 0.42, tags=['service:payment-api'])
statsd.increment('payment.requests_total', tags=['service:payment-api'])
# netcat — raw DogStatsD wire format
echo "payment.latency_ms:1240|g|#service:payment-api,namespace:production" \
| nc -u -w1 <ruptura-host> 8125
5. Application SDKs
Go
import (
"github.com/benfradjselim/ruptura/sdk/go/ruptura"
"context"
)
client := ruptura.New(ruptura.Config{
URL: "http://ruptura:8080",
APIKey: os.Getenv("RUPTURA_API_KEY"),
})
// Read workload health
snap, err := client.GetRupture(ctx, "production", "payment-api")
fmt.Printf("health=%.0f fused_r=%.2f\n", snap.HealthScore.Value, snap.FusedRuptureIndex)
Python
import ruptura
client = ruptura.Client(
url="http://ruptura:8080",
api_key=os.environ["RUPTURA_API_KEY"]
)
snap = client.get_rupture("production", "payment-api")
print(f"health={snap.health_score.value:.0f} fused_r={snap.fused_rupture_index:.2f}")
6. What Ruptura does with ingested data
OTLP metrics ──► Metric Pipeline (CA-ILR + ARIMA + HW + MAD + EWMA)
│
▼
10 KPI Signals ────────────────────────────┐
stress · fatigue · mood · pressure │
humidity · contagion · resilience │
entropy · velocity · health_score │
▼
OTLP logs ────► Sentiment Engine (pos/neg word scoring) Fusion Engine
OTLP traces ──► Span Window (error_rate × latency) → FusedR Index
│
▼
anomaly events
action engine
explain narrative
FusedR thresholds:
| Value | State | Dashboard colour |
|---|---|---|
| < 1.5 | normal | green |
| 1.5–2.5 | warning | yellow — event emitted |
| 2.5–4.0 | critical | orange — action recommended |
| > 4.0 | emergency | red — auto-action if autopilot edition |
Once calibration completes (~25 minutes of data, 100 analyzer ticks), Ruptura switches from fixed thresholds to adaptive per-workload baselines (z-score deviation from Welford rolling mean).