Skip to main content

fabric-capacity-monitor

Monitor Microsoft Fabric capacity usage from the command line — utilization, throttling risk, overage carryforward and per-item consumption — without a Power BI Pro licence.

Microsoft's Fabric Capacity Metrics app is a Power BI app. On any F SKU below F64, every viewer of Power BI content needs a Pro or PPU licence, so on an F2/F4/F8 the app that tells you how your capacity is doing is behind a per-seat paywall. This tool reads the same underlying reality from free REST APIs and renders it as text, JSON, or a self-contained HTML dashboard that anyone can open.

$ fabric-capacity-monitor report --days 14 --by-item
$ fabric-capacity-monitor report --html capacity.html

Install

pip install fabric-capacity-monitor          # core
pip install "fabric-capacity-monitor[azure]" # adds DefaultAzureCredential support

Requires Python 3.13+.

Authentication

Read-only. Everything used is available to a workspace viewer — no capacity-admin role, no Power BI licence.

--auth How
azure-cli (default) az login, then the tool shells out to az account get-access-token
default DefaultAzureCredential (managed identity, env vars, CLI, …) — needs the [azure] extra
env AZURE_TENANT_ID / AZURE_CLIENT_ID / AZURE_CLIENT_SECRET

ARM permissions (Reader on the capacity's subscription) are optional but recommended: without them you lose the SKU, region, paused/resumed history and cost, and the CU budget has to be supplied via config.

How CU is calculated

Spark is exact. Fabric bills a Spark session for its whole vCore allocation over the session's lifetime, and publishes the rate: two Spark vCores = one capacity unit.

vcores     = driver_cores + max_executors * executor_cores
cu_seconds = (vcores / 2) * running_duration_seconds

Session durations come from GET /v1/workspaces/{id}/spark/livySessions; the vCore count comes from GET /v1/workspaces/{id}/spark/pools, because the per-session core fields the API documents are not currently populated.

Everything else is estimated from published rates and marked est / ~ in the output. Pipeline orchestration is charged per activity run and no public API exposes activity counts, so pipeline CU is reported as a lower bound. Rates live in rates.toml, each with a documentation link and an "as of" date, and any of them can be overridden in your config file.

Smoothing and throttling follow Fabric's own model. Background operations are spread evenly over the 2,880 thirty-second windows after they finish, and throttling is decided by the mean utilization of a forward window:

Throttle Forward window Effect
Interactive delay 10 minutes user-triggered operations are delayed
Interactive rejection 60 minutes user-triggered operations are rejected
Background rejection 24 hours scheduled jobs are rejected

High-concurrency sessions: read the per-item table carefully

When a workspace has high concurrency enabled for pipeline runs, Fabric opens one Spark session per stage and names it after the notebook that opened it. Notebooks that later join that session produce no session record at all.

  • Capacity totals are unaffected — the session is the billed unit and is counted once.
  • Per-notebook attribution is not available. A row showing 470k CU-s against one notebook may really be a dozen notebooks sharing its session.

The tool detects this and labels the breakdown "by Spark session (attributed to session opener)" rather than pretending otherwise.

Two ways to get true per-notebook figures:

  1. Turn off notebookPipelineRunEnabled in the workspace's Spark settings, at the cost of a session start per notebook.

  2. Supply a sub-run resolver. Fabric exposes the Livy session id to running notebook code, so if your notebooks already log their own runtime next to it, you have everything needed. Implement one method and fabric_capacity_monitor.subruns.apply_subruns will redistribute each session's CU in proportion to the durations you return, preserving the capacity total exactly:

    class MyResolver:
        def resolve(self, session_id: str) -> list[SubRun]:
            # -> [SubRun(name="20_silver_transform_accounts", duration_seconds=88.0), ...]
            ...
    

    Sessions the resolver doesn't recognise are left attributed to their opener rather than guessed at, and a resolver that raises never loses a session's CU.

What is not covered

  • OneLake transactions, SQL analytics endpoint queries, semantic model refreshes and Eventhouse uptime. No free API exposes their CU; they are listed explicitly as not counted rather than silently dropped.
  • Dataflow Gen2 refreshes triggered from inside a pipeline register no job instances, so there is no duration to price.
  • The Metrics app's Storage page.

History is limited to what the Spark API retains — about 30 days. Use --json if you want to accumulate more.

Approaches that don't work

Recorded so nobody re-derives them:

  • Azure Monitor platform metrics. There are none for Microsoft.Fabric/capacities; that namespace only exists for the legacy Microsoft.PowerBIDedicated/capacities.
  • Workspace monitoring (the monitoring Eventhouse). Its KQL database has no Spark, notebook, pipeline or capacity tables — workspace monitoring has never covered Spark.
  • Real-Time Hub capacity events (Microsoft.Fabric.Capacity.Summary / .Operation). These are the exact whole-capacity CU feed, and on a large SKU they're the right answer. But consuming them needs an Eventstream at 0.222 CU/h flat plus 0.778–2.333 CU/h for the processor, and Summary events fire every 30 seconds so it never goes idle — on an F4 that is 5–60% of the entire capacity, permanently. Worth it above F64; not below.
  • Querying the Capacity Metrics app's semantic model. Needs the Pro licence this tool exists to avoid.

Configuration

Optional, at ~/.config/fabric-capacity-monitor/config.toml or via --config:

default_capacity = "my-capacity"

[aliases]
prod = "my-prod-capacity"

[rates.spark]
vcores_per_cu = 2.0   # override if Microsoft changes a rate before this package does

Exit codes

0 healthy · 1 a throttling threshold was crossed · 2 configuration or auth failure. Suitable for CI.

Licence

MIT.

Metadata

Release files for fabric-capacity-monitor 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fabric-capacity-monitor 0.1.0
File Size Uploaded
fabric_capacity_monitor-0.1.0.tar.gz 35.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fabric-capacity-monitor 0.1.0
File Interpreter ABI Platform
fabric_capacity_monitor-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 74.3 kB

Release files / fabric_capacity_monitor-0.1.0.tar.gz

Download URL fabric_capacity_monitor-0.1.0.tar.gz
Size 35.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f411fa7e26de42998cbf5c0a9ef41e18817f0f81cf8387814e94b6cf2da61654
BLAKE2b-256 checksum
How to use checksums
71c20b49ea53cf580dc30c0ffdf2f7100c15ba46bf8f7ef5df2c68f5131de0de
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 10, 2026.

Transparency log

Release files / fabric_capacity_monitor-0.1.0-py3-none-any.whl

Download URL fabric_capacity_monitor-0.1.0-py3-none-any.whl
Size 38.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5089459bf527dc04d1e38bb6d665a3c02c790f101f4e52e69616aca4a4fbefdc
BLAKE2b-256 checksum
How to use checksums
95c7df9aff4287d4002c2f33d7e94cfb06d9cadf6d4448b3f71939183a84aebb
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 10, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page