Vector is a high-performance observability data pipeline that routes logs, metrics, and traces between sources (Kubernetes, files, syslog) and sinks (Elasticsearch, Datadog, S3, Kafka). When Vector goes silent — due to a crashed process, a blocked sink, or buffer saturation — your entire observability stack loses data without any indication that collection has stopped.
In this tutorial you'll set up uptime monitoring for your Vector deployments using Vigilmon — free tier, no credit card required.
Why Vector needs external monitoring
Vector processes your observability data, which means Vector failures are invisible from inside the systems you're trying to observe. Key failure modes:
- Vector process crashes — the systemd service or Kubernetes pod restarts, losing buffered events during the restart window; silently drops data
- Sink backpressure — an Elasticsearch or Kafka sink falls behind; Vector's in-memory buffers fill up; upstream sources begin dropping new events
- Disk buffer saturation — Vector's disk-based buffer fills the partition; new events are dropped; the partition may fill to 100% and crash the host
- Source disconnection — a file source stops following rotated logs; the
docker_logssource loses connection to the Docker daemon; data silently stops flowing - Transform latency spike — a VRL (Vector Remap Language) transform doing heavy regex or JSON parsing causes event queue buildup upstream
- TLS certificate expiry on sinks — HTTPS sinks begin rejecting connections; Vector retries indefinitely but data never lands at the destination
- API endpoint unavailable — Vector's built-in HTTP API (used for health checks and topology inspection) becomes unreachable, hiding all diagnostic information
External monitoring gives you an independent heartbeat for both Vector's process health and the end-to-end data pipeline.
What you'll need
- A running Vector deployment (systemd service, Docker container, or Kubernetes DaemonSet)
- Vector's HTTP API enabled (see Step 1)
- A free Vigilmon account (sign up takes 30 seconds)
Step 1: Enable Vector's built-in HTTP API
Vector ships with an HTTP API that exposes health, topology, and component metrics. Enable it in your Vector config:
# vector.toml
[api]
enabled = true
address = "0.0.0.0:8686"
# Set to false in production to disable the GraphQL playground
playground = false
For Kubernetes deployments using the Vector Helm chart:
# values.yaml
customConfig:
api:
enabled: true
address: 0.0.0.0:8686
playground: false
service:
ports:
- name: api
port: 8686
protocol: TCP
Verify the API is running:
curl http://localhost:8686/health
# {"ok":true}
# List all configured components
curl http://localhost:8686/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ components { nodes { componentId componentType } } }"}'
Step 2: Monitor Vector process health
Vector's /health endpoint is the fastest liveness check. It returns {"ok":true} only when the Vector process is fully initialized and not in a crash loop.
Log in to Vigilmon and navigate to Monitors → Add Monitor:
For systemd/Docker deployments:
| Field | Value |
|-------|-------|
| Monitor type | HTTP |
| Name | Vector Pipeline (primary) |
| URL | http://<vector-host>:8686/health |
| HTTP method | GET |
| Expected status | 200 |
| Response must contain | "ok":true |
| Check interval | 1 minute |
| Regions | Select 3+ globally distributed regions |
For Kubernetes DaemonSet (per-node monitoring):
Expose the API via a NodePort or headless service, then add one monitor per critical node or use a load-balanced service endpoint that returns healthy only when all pods are healthy.
# vector-api-service.yaml
apiVersion: v1
kind: Service
metadata:
name: vector-api
namespace: vector
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: vector
ports:
- name: api
port: 8686
targetPort: 8686
Step 3: Monitor event throughput with a custom health endpoint
A healthy Vector process that isn't processing events is still a failure. Build a throughput probe that checks recent event counts:
# vector-throughput-probe/app.py
import requests
from flask import Flask, jsonify
import time
app = Flask(__name__)
VECTOR_API = "http://localhost:8686"
MIN_EVENTS_PER_MINUTE = 100 # Set to expected minimum throughput
# GraphQL query to get component-level event counts
THROUGHPUT_QUERY = """
{
sources {
nodes {
componentId
metrics {
receivedEventsTotal {
receivedEventsTotal
timestamp
}
}
}
}
}
"""
last_counts = {}
last_check = 0
@app.route('/health/throughput')
def throughput_health():
global last_counts, last_check
try:
resp = requests.post(
f'{VECTOR_API}/graphql',
json={'query': THROUGHPUT_QUERY},
timeout=5
)
resp.raise_for_status()
data = resp.json()
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 503
sources = data.get('data', {}).get('sources', {}).get('nodes', [])
now = time.time()
issues = []
for source in sources:
component_id = source['componentId']
total = source.get('metrics', {}).get('receivedEventsTotal', {})
current_count = total.get('receivedEventsTotal', 0)
if component_id in last_counts and last_check > 0:
elapsed_minutes = (now - last_check) / 60
rate = (current_count - last_counts[component_id]) / elapsed_minutes
if rate < MIN_EVENTS_PER_MINUTE:
issues.append({
'source': component_id,
'events_per_minute': round(rate, 1),
'minimum': MIN_EVENTS_PER_MINUTE,
})
last_counts[component_id] = current_count
last_check = now
if issues:
return jsonify({'status': 'low_throughput', 'sources': issues}), 503
return jsonify({
'status': 'ok',
'source_count': len(sources),
'checked_at': now,
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9094)
Add a Vigilmon monitor:
| Field | Value |
|-------|-------|
| Monitor type | HTTP |
| Name | Vector Event Throughput |
| URL | http://<vector-host>:9094/health/throughput |
| Expected status | 200 |
| Response must contain | "status":"ok" |
| Check interval | 2 minutes |
Step 4: Monitor buffer utilization
Vector's disk buffers can fill when sinks are slow or offline. A full buffer means data loss. Monitor buffer utilization:
# Vector exposes buffer metrics via its GraphQL API
curl -s http://localhost:8686/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ sinks { nodes { componentId metrics { bufferEventsTotal { bufferEventsTotal } bufferByteSize { bufferByteSize } } } } }"}' \
| python3 -m json.tool
Build a buffer health endpoint:
// buffer-health-probe/index.js
const axios = require('axios');
const express = require('express');
const app = express();
const VECTOR_API = process.env.VECTOR_API || 'http://localhost:8686';
const MAX_BUFFER_BYTES = parseInt(process.env.MAX_BUFFER_BYTES || '1073741824'); // 1GB default
const BUFFER_QUERY = `{
sinks {
nodes {
componentId
metrics {
bufferByteSize { bufferByteSize }
bufferEventsTotal { bufferEventsTotal }
}
}
}
}`;
app.get('/health/buffers', async (req, res) => {
try {
const { data } = await axios.post(
`${VECTOR_API}/graphql`,
{ query: BUFFER_QUERY },
{ timeout: 5000 }
);
const sinks = data?.data?.sinks?.nodes || [];
const saturated = [];
for (const sink of sinks) {
const bufferBytes = sink.metrics?.bufferByteSize?.bufferByteSize || 0;
const utilization = bufferBytes / MAX_BUFFER_BYTES;
if (utilization > 0.8) {
saturated.push({
sink: sink.componentId,
buffer_bytes: bufferBytes,
utilization_pct: Math.round(utilization * 100),
});
}
}
if (saturated.length > 0) {
return res.status(503).json({
status: 'saturated',
sinks: saturated,
});
}
res.json({ status: 'ok', sinks_checked: sinks.length });
} catch (err) {
res.status(503).json({ status: 'error', message: err.message });
}
});
app.listen(9095);
Add a Vigilmon monitor:
| Field | Value |
|-------|-------|
| Monitor type | HTTP |
| Name | Vector Buffer Utilization |
| URL | http://<vector-host>:9095/health/buffers |
| Expected status | 200 |
| Response must contain | "status":"ok" |
| Check interval | 2 minutes |
Step 5: Monitor sink connectivity with TCP checks
Even before Vector starts rejecting events, you can detect sink connectivity issues with TCP monitors. Add one per critical sink:
Elasticsearch sink:
| Field | Value |
|-------|-------|
| Monitor type | TCP |
| Name | Vector → Elasticsearch (sink) |
| Host | <elasticsearch-host> |
| Port | 9200 |
| Check interval | 1 minute |
Kafka sink:
| Field | Value |
|-------|-------|
| Monitor type | TCP |
| Name | Vector → Kafka Broker (sink) |
| Host | <kafka-broker-host> |
| Port | 9092 |
| Check interval | 1 minute |
These TCP monitors alert you when the sink is unreachable, even before Vector's own retry logic gives up and starts dropping events.
Step 6: Monitor Vector's component error rate
Vector tracks per-component error rates. An elevated error rate on a source or sink indicates data is being dropped:
# Query error metrics via GraphQL
curl -s http://localhost:8686/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ sources { nodes { componentId metrics { receivedBytesTotal { receivedBytesTotal } } } } }"}'
Add the error rate check to your throughput probe or create a dedicated endpoint that returns non-200 when the error rate on any component exceeds a threshold:
# In your existing probe, add:
ERROR_QUERY = """
{
components {
nodes {
componentId
componentType
metrics {
errorsTotal {
errorsTotal
}
}
}
}
}
"""
@app.route('/health/errors')
def error_health():
try:
resp = requests.post(
f'{VECTOR_API}/graphql',
json={'query': ERROR_QUERY},
timeout=5
)
data = resp.json()
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 503
components = data.get('data', {}).get('components', {}).get('nodes', [])
elevated = [
{'component': c['componentId'], 'errors': c['metrics']['errorsTotal']['errorsTotal']}
for c in components
if c.get('metrics', {}).get('errorsTotal', {}).get('errorsTotal', 0) > 0
]
if elevated:
return jsonify({'status': 'errors_detected', 'components': elevated}), 503
return jsonify({'status': 'ok'})
Step 7: Configure alerts
In Vigilmon, go to Alerts → Alert Channels and set up your notification channels.
Recommended alert policy for Vector monitors:
| Monitor | Alert after | Rationale | |---------|-------------|-----------| | Vector Health HTTP | 1 failure | Process crash; all data collection stops | | Event Throughput HTTP | 2 failures | Allow one check for pipeline startup ramp | | Buffer Utilization HTTP | 2 failures | Give time for sink recovery before alerting | | Sink TCP monitors | 2 failures | Brief network hiccups vs. real sink failure |
Enable Recovery alerts on all monitors — knowing when Vector resumes processing is as important as knowing it stopped.
Step 8: Create a pipeline observability status page
Vector is often the single pipeline delivering logs and metrics to your observability tools. Create a status page your team can check before investigating "why is Grafana empty?":
- In Vigilmon, go to Status Pages → Create Status Page
- Name it "Observability Pipeline Health"
- Group monitors as:
- Collection: Vector Health, Event Throughput
- Pipeline: Buffer Utilization, Error Rate
- Destinations: Elasticsearch TCP, Kafka TCP, (any other sinks)
- Share the URL in your #ops or #observability Slack channel
What you're monitoring now
| Monitor | What it detects | |---------|-----------------| | Vector Health HTTP | Process crash, restart loop, initialization failure | | Event Throughput HTTP | Sources going silent, pipeline stalls | | Buffer Utilization HTTP | Sink backpressure causing data loss risk | | Sink TCP monitors | Connectivity failures before Vector starts dropping data | | Error Rate HTTP | Per-component drops and processing failures |
Conclusion
Vector is the foundation of your observability pipeline, which makes it especially easy to miss failures — if Vector stops collecting data, your dashboards go quiet but don't alert. Vigilmon gives you an independent external heartbeat that catches process crashes, buffer saturation, throughput drops, and sink connectivity failures before they turn into gaps in your observability data.
Sign up for a free Vigilmon account and make your observability pipeline observable.