MetriSight
A lightweight, self-hosted metric anomaly dashboard for developers. Detects anomalies in time-series metrics using statistical methods — no ML expertise or expensive APM tools required.
Status: alpha. Defaults and the Python API may still change before 1.0; breaking changes are recorded in the changelog. It is safe to point at a production Prometheus — MetriSight only ever issues read-only GET queries against /api/v1/query_range and /api/v1/status/buildinfo, and never writes to your metrics.
Features
- Prometheus live streaming — connect to any Prometheus instance, auto-refresh on a configurable interval
- Real-time anomaly detection using Z-score and Moving Average methods
- Interactive dashboard with Plotly charts and Streamlit
- CSV upload — bring your own metric data from any source
- Simulated metrics (CPU, Memory, Latency) with injected anomalies for demo
- Configurable thresholds via sidebar controls
Quick Start
Requires Python 3.10 or newer.
pip install metrisight
metrisight
The dashboard opens at http://localhost:8501. By default it runs with simulated metrics — switch to Prometheus (Live) or Upload CSV in the sidebar.
Arguments are passed through to Streamlit, so you can change the port:
metrisight --server.port 8502
From a clone
git clone https://github.com/pallaprolus/metrisight.git
cd metrisight
pip install -e .
metrisight
Connecting to Prometheus (Live Streaming)
MetriSight connects directly to your Prometheus instance and streams metrics with configurable auto-refresh.
Setup
- Select Prometheus (Live) in the sidebar
- Enter your Prometheus URL (e.g.,
http://localhost:9090) - Enter a PromQL query (e.g.,
rate(node_cpu_seconds_total{mode="idle"}[5m])) - Choose a lookback window (1h, 6h, 24h, or 7 days)
- Set auto-refresh interval (15s, 30s, 1m, or 5m) for live monitoring
- Click Test Connection to verify connectivity
Example PromQL queries
# CPU usage rate
rate(node_cpu_seconds_total{mode="idle"}[5m])
# Memory usage percentage
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
# HTTP request latency (p95)
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# HTTP error rate
rate(http_requests_total{status=~"5.."}[5m])
# Disk I/O utilization
rate(node_disk_io_time_seconds_total[5m])
Queries that match several series
A PromQL expression returns one series per label set — rate(node_cpu_seconds_total[5m])
on a 4-core box matches four. When a query matches more than one, MetriSight says how
many and gives you a picker rather than charting an arbitrary one:
This query matched 4 series. Pick one below, or add a label matcher or an aggregation (e.g.
avg by (job) (...)) to narrow it.
To reduce to a single series in the query itself, aggregate:
# average across all CPUs instead of one series per CPU
avg(rate(node_cpu_seconds_total{mode="idle"}[5m]))
# one series per job
avg by (job) (rate(http_requests_total[5m]))
Authentication
MetriSight supports authenticated Prometheus instances. Select the auth method in the sidebar under the Prometheus section.
| Method | When to use | Setup |
|---|---|---|
| None | Local/internal Prometheus without auth | Default, no config needed |
| Bearer Token | Grafana Cloud, Thanos, Cortex, managed Prometheus | Paste your API token |
| Basic Auth | Prometheus behind nginx/Apache reverse proxy | Enter username + password |
Credentials are passed via HTTP headers only — they are never logged, stored on disk, or displayed in the UI (password fields are masked).
Grafana Cloud example:
- Get your API token from Grafana Cloud > your stack > Prometheus > Details
- Set Prometheus URL to your Grafana Cloud Prometheus endpoint (e.g.,
https://prometheus-prod-01-eu-west-0.grafana.net/api/prom) - Select Bearer Token and paste your API key
- Click Test Connection to verify — you'll see the Prometheus version if auth succeeds, or a
401 Unauthorizederror if the token is wrong
How it works
- MetriSight queries the Prometheus
/api/v1/query_rangeendpoint - The lookback window determines how far back to fetch (rolling window)
- Auto-refresh re-queries Prometheus on the set interval, so the chart updates with live data
- Anomaly detection runs on each refresh against the full lookback window
- Prometheus stores timestamps in UTC; the chart displays them in the local timezone of the machine running MetriSight
- Stale (
NaN) and infinite samples are dropped before detection runs, since either one distorts every rolling window containing it
Lookback window guide
| Window | Best for | Typical resolution |
|---|---|---|
| 1 hour | Real-time incident triage | 15s |
| 6 hours | Shift monitoring | 30s - 1m |
| 24 hours | Daily pattern analysis | 1m |
| 7 days | Weekly trend detection | 5m |
Other Data Sources
CSV Upload
Upload a CSV file with two columns:
timestamp,value
2024-01-15 10:00:00,45.2
2024-01-15 10:01:00,47.8
2024-01-15 10:02:00,44.1
Rows are sorted by timestamp on load, and rows with an unparseable timestamp, a non-numeric or non-finite value, or a duplicate timestamp are dropped — the count is reported under the upload. Ordering matters because detection uses trailing rolling windows.
Exporting from other tools
CloudWatch:
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 --metric-name CPUUtilization \
--start-time 2024-01-15T00:00:00Z --end-time 2024-01-15T23:59:59Z \
--period 60 --statistics Average --output json \
| python3 -c "
import json, sys, csv
data = json.load(sys.stdin)['Datapoints']
data.sort(key=lambda x: x['Timestamp'])
w = csv.writer(sys.stdout)
w.writerow(['timestamp', 'value'])
for d in data:
w.writerow([d['Timestamp'], d['Average']])
" > cloudwatch_cpu.csv
Datadog:
curl -s "https://api.datadoghq.com/api/v1/query?from=$(date -d '24 hours ago' +%s)&to=$(date +%s)&query=avg:system.cpu.user{*}" \
-H "DD-API-KEY: $DD_API_KEY" -H "DD-APPLICATION-KEY: $DD_APP_KEY" \
| python3 -c "
import json, sys, csv
from datetime import datetime
data = json.load(sys.stdin)['series'][0]['pointlist']
w = csv.writer(sys.stdout)
w.writerow(['timestamp', 'value'])
for ts_ms, val in data:
w.writerow([datetime.fromtimestamp(ts_ms / 1000).isoformat(), val])
" > datadog_cpu.csv
Programmatic Usage
import pandas as pd
from metrisight.detector import detect_zscore, get_anomaly_summary
df = pd.read_csv("my_metrics.csv")
df["timestamp"] = pd.to_datetime(df["timestamp"])
result = detect_zscore(df, threshold=3.0)
summary = get_anomaly_summary(result)
print(f"Found {summary['anomaly_count']} anomalies ({summary['anomaly_pct']}%)")
Querying Prometheus directly — query_series returns every matching label set:
from metrisight import query_series, detect_moving_avg
for series in query_series("http://localhost:9090", "up", lookback_hours=6):
result = detect_moving_avg(series.df, window=20, threshold=2.0)
print(series.name, int(result["is_anomaly"].sum()), "anomalies")
query_prometheus(...) remains available and returns the first matching series
as a DataFrame.
How It Works
MetriSight uses two statistical methods to detect anomalies:
- Z-Score Detection — flags data points that deviate more than N standard deviations from the mean
- Moving Average Detection — flags data points that deviate from a trailing rolling mean by more than N rolling standard deviations. The window is trailing rather than centered, so each point is judged only against data that preceded it — the newest sample in a live stream is scored the same way as every other point.
Project Structure
metrisight/
├── metrisight/
│ ├── app.py # Streamlit dashboard
│ ├── cli.py # `metrisight` launcher
│ ├── simulator.py # Generates realistic fake metrics
│ ├── detector.py # Anomaly detection algorithms
│ ├── prometheus.py # Prometheus HTTP API client
│ ├── data.py # Shared series cleaning / ordering
│ └── charts.py # Plotly chart builders
└── tests/
├── test_charts.py # Chart construction tests
├── test_cli.py # CLI / packaging tests
├── test_data.py # Series hygiene tests
├── test_detector.py # Detection algorithm tests
├── test_prometheus.py # Prometheus client tests
└── test_simulator.py # Simulated data tests
Changelog
See CHANGELOG.md. Note that 0.2.0 requires Python 3.10 or newer.
License
MIT
Metadata
Release files for metrisight 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| metrisight-0.2.0.tar.gz | 31.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| metrisight-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 51.4 kB
Release files / metrisight-0.2.0.tar.gz
| Download URL | metrisight-0.2.0.tar.gz |
|---|---|
| Size | 31.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7a16475c56ce9b6f8067672f84adf5c1843a71b3b59d42408640ddc8e2a5e962
|
|
BLAKE2b-256 checksum How to use checksums |
02a6e2acb6805490b51b0bfd644aee3e7bdc89cd78d2499d36bf2c45e288e649
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency logRelease files / metrisight-0.2.0-py3-none-any.whl
| Download URL | metrisight-0.2.0-py3-none-any.whl |
|---|---|
| Size | 20.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f3f3a0e47ba2985b0e6548a1ab067e9d5257d1c29150dfadabe7636e5c51ff36
|
|
BLAKE2b-256 checksum How to use checksums |
ccf3913eeb8ba2c83b200d0cbf392262966f2734fadb68ae470d24436a39e337
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency log