{"id":49157680,"url":"https://github.com/donchanee/metricops","last_synced_at":"2026-04-22T10:05:45.891Z","repository":{"id":352126825,"uuid":"1213553186","full_name":"donchanee/metricops","owner":"donchanee","description":"Prometheus metric governance CLI for self-hosted operators","archived":false,"fork":false,"pushed_at":"2026-04-18T01:26:50.000Z","size":95,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-18T02:41:33.754Z","etag":null,"topics":["cli","cost-optimization","golang","grafana","metrics","observability","prometheus","sre"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/donchanee.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-17T13:59:26.000Z","updated_at":"2026-04-18T01:26:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/donchanee/metricops","commit_stats":null,"previous_names":["donchanee/metricops"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/donchanee/metricops","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donchanee%2Fmetricops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donchanee%2Fmetricops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donchanee%2Fmetricops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donchanee%2Fmetricops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/donchanee","download_url":"https://codeload.github.com/donchanee/metricops/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donchanee%2Fmetricops/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32130813,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T08:34:57.708Z","status":"ssl_error","status_checked_at":"2026-04-22T08:34:55.583Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cost-optimization","golang","grafana","metrics","observability","prometheus","sre"],"created_at":"2026-04-22T10:05:45.481Z","updated_at":"2026-04-22T10:05:45.882Z","avatar_url":"https://github.com/donchanee.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# metricops\n\n**Prometheus metric governance for self-hosted operators.**\n\n[![CI](https://github.com/donchanee/metricops/actions/workflows/ci.yml/badge.svg)](https://github.com/donchanee/metricops/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/donchanee/metricops?sort=semver)](https://github.com/donchanee/metricops/releases)\n[![Go Reference](https://pkg.go.dev/badge/github.com/donchanee/metricops.svg)](https://pkg.go.dev/github.com/donchanee/metricops)\n[![License](https://img.shields.io/github/license/donchanee/metricops)](./LICENSE)\n\n`metricops analyze` reads your Prometheus TSDB, Grafana dashboards, and alert\nrules and tells you three things you probably can't answer today:\n\n1. **Which metrics are you paying to store but nobody queries?**\n2. **Which metrics and labels are quietly eating most of your series budget?**\n3. **How many bytes per day would you save if you dropped the dead weight?**\n\nAll local. No network calls. No telemetry. No cloud service. Your TSDB\nmetadata and dashboards never leave the machine `metricops` runs on.\n\n---\n\n## Example output\n\n```markdown\n# metricops Report\nGenerated: 2026-04-17T12:00:00Z · Schema: 1.0\n\n## Summary\n\n| Metric                    | Value                       |\n|---------------------------|-----------------------------|\n| Total metrics             | 80                          |\n| Unused metrics            | 21                          |\n| Total active series       | 76,475                      |\n| Estimated daily bytes     | 880,991,987 (840.18 MiB)    |\n| Estimated monthly bytes   | 26,429,759,610 (24.61 GiB)  |\n| Bytes per sample assumed  | 2.00                        |\n\n## Unused Metrics\n21 metrics appear in TSDB but are not referenced by any dashboard, alert,\nor recording rule.\n\n| Metric                                 | Active Series | Bytes/day    |\n|----------------------------------------|--------------:|-------------:|\n| `http_request_duration_seconds_bucket` |        15,013 |  172,949,760 |\n| `http_response_size_bytes`             |         2,640 |   30,412,800 |\n| `legacy_worker_queue_depth`            |            26 |      299,520 |\n...\n\n## Recommendations\n21 actions identified. Total estimated daily savings: 224.87 MiB.\n\n- `drop_metric` **`http_request_duration_seconds_bucket`** — saves ~164.94 MiB/day\n...\n```\n\nAsk for JSON with `--format=json` for CI pipelines and scripts. The v1.0 JSON\nschema is byte-deterministic across runs (same inputs → byte-identical output,\na CI gate in this repo).\n\n---\n\n## Install\n\n### Go\n\n```bash\ngo install github.com/donchanee/metricops/cmd/metricops@latest\n```\n\n### Pre-built binaries\n\nGrab the archive for your OS and arch from the\n[releases page](https://github.com/donchanee/metricops/releases) and put the\n`metricops` binary on your `PATH`.\n\nSupported: linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64.\n\n### Build from source\n\n```bash\ngit clone https://github.com/donchanee/metricops\ncd metricops\ngo build -o metricops ./cmd/metricops\n```\n\n---\n\n## Quick start\n\nYou need three inputs:\n\n1. The output of `promtool tsdb analyze \u003cblock\u003e` (a text file).\n2. Your Grafana dashboards as JSON files in a directory (optional).\n3. Your Prometheus rule files as YAML in a directory (optional).\n\n```bash\n# Capture TSDB state (takes a minute on a large block; that's promtool's time, not ours)\npromtool tsdb analyze /var/lib/prometheus/\u003cblock-id\u003e \u003e tsdb-analyze.txt\n\n# Export dashboards (or point at a git-mirrored dashboards-as-code directory)\n# Skip this flag if you want a rules-only run.\n\n# Analyze\nmetricops analyze \\\n  --tsdb=tsdb-analyze.txt \\\n  --grafana=./dashboards \\\n  --rules=/etc/prometheus/rules\n```\n\nTry it on synthetic data right now — this repo ships a fixture generator:\n\n```bash\ngo run testdata/fixtures/generate.go -out ./testdata/fixtures\ngo run ./cmd/metricops analyze \\\n  --tsdb=./testdata/fixtures/tsdb-analyze.txt \\\n  --grafana=./testdata/fixtures/dashboards \\\n  --rules=./testdata/fixtures/rules\n```\n\n---\n\n## CLI reference\n\n```text\nmetricops analyze [flags]\n\nFlags:\n  --tsdb string             promtool tsdb analyze output (file or '-' for stdin) [required]\n  --grafana string          Grafana dashboard JSON file or directory\n  --rules string            Prometheus rule YAML file or directory\n  --format string           output format: markdown (default), md, or json\n  --schema string           JSON schema version (default \"1.0\"; only 1.0 supported in v0.x)\n  --strict                  promote per-file parse warnings to exit 1\n  --bytes-per-sample float  assumed bytes per sample, compressed TSDB (default 2.00)\n  --fail-on string          exit 1 when findings of this kind exist (e.g. 'findings')\n  --timeout duration        analysis deadline (default 5m)\n  --progress                emit stage-based progress on stderr\n```\n\n### Exit codes\n\n| Code | Meaning                                                                |\n|------|------------------------------------------------------------------------|\n| 0    | Success, with or without findings (unless `--fail-on` matched).        |\n| 1    | Findings present and matched `--fail-on`, or strict parse warnings.    |\n| 2    | Invalid flags, unreadable input, unsupported schema.                   |\n\n---\n\n## How it works\n\n```text\n  ┌───────────────────┐         ┌───────────────────┐\n  │  promtool tsdb    │         │  Grafana JSON    +│\n  │  analyze output   │         │  Prom rule YAML   │\n  └─────────┬─────────┘         └─────────┬─────────┘\n            │                             │\n            ▼                             ▼\n    ┌──────────────┐            ┌───────────────────┐\n    │  parse.TSDB  │            │ parse.Grafana/Rules\n    └──────┬───────┘            └─────────┬─────────┘\n           │ []*Metric                    │ []Reference\n           │                              │\n           └──────────┬───────────────────┘\n                      ▼\n             ┌─────────────────┐\n             │  builder.Build  │  ← promqlx.MetricNames\n             └────────┬────────┘     walks each Expr AST\n                      │ *Model        to attribute refs\n                      ▼\n             ┌─────────────────┐\n             │   analyze.*     │  DetectUnused\n             │                 │  DetectHotspots\n             │                 │  EstimateSummary\n             │                 │  BuildRecommendations\n             └────────┬────────┘\n                      ▼\n             ┌─────────────────┐\n             │   render.*      │  Markdown or JSON\n             └─────────────────┘\n                      ▼\n                   stdout\n```\n\nEvery stage is a pure function; parsers do the only I/O. The whole pipeline\nruns under `--timeout` (default 5m) so a cron job can't hang your runner.\n\n---\n\n## CI integration\n\nUse `--fail-on=findings` to block PRs that introduce unused metrics or\ncardinality hotspots.\n\n```yaml\n# .github/workflows/prom-governance.yml\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Install metricops\n        run: go install github.com/donchanee/metricops/cmd/metricops@latest\n      - name: Export TSDB state\n        run: |\n          ssh prod-prom 'promtool tsdb analyze /var/lib/prometheus/\u003cblock\u003e' \u003e tsdb.txt\n      - name: Analyze\n        run: |\n          metricops analyze \\\n            --tsdb=tsdb.txt \\\n            --grafana=./dashboards \\\n            --rules=./rules \\\n            --format=json \\\n            --fail-on=findings \u003e report.json\n      - uses: actions/upload-artifact@v4\n        with:\n          name: metricops-report\n          path: report.json\n```\n\n---\n\n## Data privacy\n\n`metricops` runs entirely on your machine. It does not:\n\n- make outbound network calls,\n- phone home with telemetry,\n- read configuration from any location you didn't point it at,\n- write outputs anywhere other than stdout and stderr.\n\nYour TSDB analysis, dashboards, and rule files stay on disk. You can run\nit on air-gapped infrastructure.\n\n---\n\n## Known limitations\n\n- **Recording-rule chains are not traversed.** A metric referenced only\n  through another recording rule's output may appear unused. v2 roadmap.\n- **Template-variable expressions** (`${var}`, `$__range`) in Grafana are\n  skipped with a warning; their metric references are not attributed.\n- **Repeat panels** in Grafana are skipped.\n- **Regex `__name__` matchers** (`{__name__=~\"foo.*\"}`) cannot be resolved;\n  metrics referenced only this way will appear unused.\n- **VictoriaMetrics / Thanos / Mimir** backends are not yet adapted; this\n  release targets vanilla Prometheus. v2 adds those via the same parser\n  contract.\n\nSee [CHANGELOG.md](./CHANGELOG.md) for the full v0.1.0 shipping notes.\n\n---\n\n## Contributing\n\nIssues and PRs welcome.\n- Small PRs merge faster. Keep one change per PR.\n- `go test ./...` and `go vet ./...` must pass.\n- New behavior needs tests.\n- The JSON schema is a compatibility surface: additive changes only within\n  v1.x; breaking changes bump the major.\n\n---\n\n## License\n\n[Apache-2.0](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdonchanee%2Fmetricops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdonchanee%2Fmetricops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdonchanee%2Fmetricops/lists"}