> ## Documentation Index
> Fetch the complete documentation index at: https://www.towbar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Prometheus

> Prometheus collects and queries metrics from applications and infrastructure.

export const UseCaseNavigation = () => {
  useLayoutEffect(() => {
    const storageKey = "towbar-use-case-open-groups";
    const groupSelector = "#sidebar li[data-title] > button[aria-expanded]";
    let restoring = false;
    let frame = 0;
    function storedGroups() {
      try {
        return new Set(JSON.parse(sessionStorage.getItem(storageKey) || "[]"));
      } catch {
        return new Set();
      }
    }
    function save(groups) {
      try {
        sessionStorage.setItem(storageKey, JSON.stringify([...groups]));
      } catch {}
    }
    function groupName(button) {
      return button.parentElement?.dataset.title;
    }
    function rememberOpenGroups() {
      const groups = new Set();
      for (const button of document.querySelectorAll(groupSelector)) {
        if (button.getAttribute("aria-expanded") === "true") {
          const name = groupName(button);
          if (name) groups.add(name);
        }
      }
      save(groups);
    }
    function restoreOpenGroups() {
      frame = 0;
      const groups = storedGroups();
      if (!groups.size) return;
      restoring = true;
      for (const button of document.querySelectorAll(groupSelector)) {
        if (groups.has(groupName(button)) && button.getAttribute("aria-expanded") === "false") {
          button.click();
        }
      }
      restoring = false;
    }
    function scheduleRestore() {
      if (!frame) frame = requestAnimationFrame(restoreOpenGroups);
    }
    function onClick(event) {
      if (restoring || !(event.target instanceof Element)) return;
      const button = event.target.closest(groupSelector);
      if (button) {
        const name = groupName(button);
        if (!name) return;
        const groups = storedGroups();
        if (button.getAttribute("aria-expanded") === "true") groups.delete(name); else groups.add(name);
        save(groups);
        return;
      }
      if (event.target.closest('a[href^="/docs/use-cases/"]')) {
        rememberOpenGroups();
      }
    }
    const observer = new MutationObserver(scheduleRestore);
    document.addEventListener("click", onClick, true);
    observer.observe(document.getElementById("sidebar") || document.body, {
      childList: true,
      subtree: true
    });
    scheduleRestore();
    return () => {
      document.removeEventListener("click", onClick, true);
      observer.disconnect();
      cancelAnimationFrame(frame);
    };
  }, []);
  return null;
};

<UseCaseNavigation />

<img className="towbar-doc-brand-logo" src="https://mintcdn.com/avgeek/Wq-9tmR7jDSzqtpH/assets/use-case-logos/prometheus.svg?fit=max&auto=format&n=Wq-9tmR7jDSzqtpH&q=85&s=f74f7a5331b127296da6c202172221db" alt="Prometheus logo" aria-hidden="true" width="24" height="24" data-path="assets/use-case-logos/prometheus.svg" />

**Upstream source:** [Current installation guide](https://prometheus.io/docs/prometheus/latest/installation/).

Prometheus needs a scrape configuration as well as a persistent metrics directory. This first instance scrapes itself only; add explicit targets before expecting host or application metrics.

## Towbar manifest

```yaml title=".towbar/services/prometheus.compose.yml" theme={"system"}
id: prometheus
name: Prometheus
file: deploy/prometheus/compose.yml
strategy: maintenance
services:
  prometheus: {}
environments:
  production:
    server: 192.0.2.10
```

## Compose project

<CodeGroup>
  ```yaml title="deploy/prometheus/compose.yml" theme={"system"}
  services:
    prometheus:
      image: prom/prometheus:v3.5.0@sha256:63805ebb8d2b3920190daf1cb14a60871b16fd38bed42b857a3182bc621f4996
      configs:
        - source: scrape
          target: /etc/prometheus/prometheus.yml
      volumes:
        - metrics:/prometheus
  configs:
    scrape:
      file: ./prometheus.yml
  volumes:
    metrics: {}
  ```

  ```yaml title="deploy/prometheus/prometheus.yml" theme={"system"}
  global:
    scrape_interval: 30s
  scrape_configs:
    - job_name: prometheus
      static_configs:
        - targets:
            - localhost:9090
  ```
</CodeGroup>

## Configure

1. Prepare the example server, connect the repository, and map `production` to the branch containing these files. Replace the example server IP.
2. Commit every file shown below under `deploy/prometheus/`. The Towbar manifest points to the Compose file; it does not create it for you.
3. Sync the repository and inspect the resolved Compose project. Save the runtime values below if this example declares any.
4. Keep this service private until you put authentication in front of its UI and API.
5. Edit `prometheus.yml` to add only targets reachable from this Compose network. The sample self-scrape cannot discover Towbar Services automatically.
6. Deploy it manually and run the verification below before enabling auto-deploy.

## Verify

Check `Status → Targets` from a trusted connection or query `up{job="prometheus"}` from the server. Back up the `metrics` volume if the historical samples matter.

For field constraints, see [Compose guide](/docs/services/modes/compose).
