A Central Monitoring Stack for a Multi-Application SaaS Ecosystem
A SaaS application can be online and still be failing its users. An API might respond while background jobs stop processing. A database might accept connections while queries become slow. A server might look healthy while one container runs out of memory. The Enterprise Monitoring Stack brings these different signals into a central monitoring environment, helping operators understand both whether applications are available and what is happening underneath them.
The project provides a Docker-based foundation for monitoring multiple SaaS applications across Linux virtual machines. It combines Prometheus for metrics, Grafana for visualisation, and Uptime Kuma for availability checks, with collectors running alongside each application.
Its purpose is to give a solo developer or a small platform team consistent operational visibility across an application portfolio.
The problem: fragmented visibility
Without a shared monitoring approach, each application tends to develop its own operational habits: a health endpoint here, container logs there, and a server dashboard somewhere else.
That makes basic questions harder to answer:
- Which applications are affected?
- Is the problem in the API, database, queue, container, or host?
- Did performance deteriorate gradually or change suddenly?
- Is a background workflow progressing even though the website still loads?
- Is the application unavailable, or has monitoring lost contact with it?
The stack addresses this by collecting comparable signals from each deployment and storing metrics centrally. Operators can investigate application behaviour alongside the infrastructure supporting it.
Two parts of one ecosystem
The architecture separates the central monitoring environment from the software that produces measurements.
flowchart TB
subgraph Apps["SaaS application environments"]
App["Application code and metrics library"]
Infra["Host, containers, proxy, and data services"]
Exporters["Infrastructure exporters"]
Endpoint["Private application metrics endpoint"]
Public["Public website or API"]
App --> Endpoint
Infra --> Exporters
end
subgraph Central["Central monitoring VM"]
Prom["Prometheus"]
Grafana["Grafana"]
Kuma["Uptime Kuma"]
Grafana -->|"Queries stored metrics"| Prom
end
Prom -->|"Scrapes over private network"| Endpoint
Prom -->|"Scrapes over private network"| Exporters
Kuma -->|"Checks public availability"| Public
The central environment collects, stores, and presents operational data. Application environments expose measurements through a common format.
This is monitoring for SaaS applications under the operator’s control: integrating their backend code and deployment infrastructure, rather than connecting to arbitrary third-party SaaS accounts.
The central environment
Three services form the core:
| Technology | Responsibility |
|---|---|
| Prometheus | Collects numerical measurements, stores their history, and evaluates alert rules. |
| Grafana | Queries Prometheus and displays metrics in dashboards. |
| Uptime Kuma | Checks configured endpoints for availability and response behaviour. |
Grafana is the central metrics dashboard. Uptime Kuma provides a complementary availability view through its own interface. They belong to the same monitoring environment, but the repository does not implement a custom dashboard that merges every signal into one application.
What runs alongside each application
Each application VM runs collectors appropriate to its workload:
| Layer | Collector or integration | Typical visibility |
|---|---|---|
| Linux host | node-exporter | CPU, memory, disk, and network usage |
| Docker containers | cAdvisor | Container resource consumption |
| Nginx | Nginx Prometheus exporter | Connections and request activity |
| Databases | PostgreSQL, MySQL, or MongoDB exporters | Database-specific operational measurements |
| Cache | Redis exporter | Memory use, connections, and cache activity |
| Message broker | RabbitMQ Prometheus plugin | Broker and queue measurements |
| Application | A private /metrics endpoint |
Request counts, latency, errors, and custom workflow metrics |
Database and cache exporters are optional Compose profiles. A deployment enables the components it actually needs.
Infrastructure collectors and application instrumentation serve different purposes. An exporter can describe a container’s memory usage, but application code must provide context such as how many jobs failed or how long an API operation took.
How status data is collected
The stack combines two perspectives.
Availability checks test whether a configured endpoint responds from the monitoring location. These help answer, “Can this service be reached?” They do not establish that every feature or every user’s network path is working.
Internal metrics describe activity and resource usage inside the deployment. These help explain slowdowns, failures, and capacity pressure.
The metrics pipeline uses a pull model: Prometheus requests measurements from each registered endpoint.
sequenceDiagram
participant User as User or background task
participant App as Application
participant Library as Metrics library
participant Prom as Prometheus
participant Dash as Grafana
User->>App: Perform an operation
App->>Library: Record count, duration, or outcome
Note over Library: Keep aggregated measurements locally
Prom->>App: Request private /metrics endpoint
App->>Library: Read current measurements
Library-->>App: Prometheus-format metrics
App-->>Prom: Return measurements
Note over Prom: Store samples and evaluate rules
Dash->>Prom: Query a time range
Prom-->>Dash: Return time-series results
Although it is natural to describe applications as “sending monitoring data,” they generally return it when Prometheus scrapes them. They do not contact Grafana directly or transmit a separate monitoring event for every request.
Prometheus discovers endpoints through configuration files. Labels associate measurements with applications, hosts, environments, and components, making it possible to query related signals together.
How the libraries inside other projects work
The application integration guides describe using standard Prometheus client libraries, including prom-client for Node.js and prometheus_client for Python.
These libraries run inside the backend application. A small integration layer connects them to HTTP middleware, framework interceptors, workers, or scheduled collectors.
The basic building blocks are:
- Counters: totals that increase, such as completed requests or failed jobs.
- Gauges: current values that rise or fall, such as active requests or waiting jobs.
- Histograms: measurements grouped into buckets, such as request durations, from which latency percentiles can be estimated.
For an API request, instrumentation records the method, a normalised route, the response status, and the elapsed time. A worker can record completed and failed jobs. Queue integration can periodically read queue state and expose the results as gauges.
The library keeps these measurements in a registry and exposes them through a private /metrics endpoint. Prometheus then collects them using the same mechanism it uses for infrastructure exporters.
Labels should describe bounded categories, such as route templates and status codes. Customer identifiers, request bodies, and raw URLs are generally unsuitable metric labels: they can disclose sensitive information and create excessive numbers of time series.
A shared integration pattern
The repository contains application preparation guides and instrumentation examples. It does not contain a separately published, proprietary monitoring SDK.
The reusable element is currently the integration pattern: consistent endpoints, metric names, labels, and instrumentation conventions. Each application implements that contract using its own framework and a standard client library.
Consistency matters because central queries and alert rules depend on the metric names and labels that applications expose. Installing a library alone does not make an application compatible with every dashboard or alert.
What “real-time” means here
This is near-real-time monitoring rather than a continuous stream of individual events.
The current Prometheus configuration scrapes metrics every 15 seconds and evaluates alert rules every 15 seconds. Dashboard refresh settings, query windows, and alert waiting periods introduce additional delay.
Counters can preserve activity between scrapes: a burst of completed requests still contributes to the next collected total. A short-lived gauge spike, however, may occur entirely between samples and go unseen.
Alerts can also require a condition to persist before firing. That helps distinguish a sustained problem from a brief fluctuation.
A failed scrape needs interpretation, too. It means Prometheus could not collect measurements from an endpoint; it does not, by itself, prove that the public application is down. Availability checks provide another piece of evidence.
From measurements to useful diagnosis
The benefit comes from comparing signals.
Consider an illustrative case where a website remains reachable but background processing slows down:
- Availability checks continue to pass.
- Application metrics show an increasing number of waiting jobs.
- Worker completion rates fall.
- Database metrics show connection pressure.
- Host and container metrics help establish whether resource exhaustion is also involved.
This narrows the investigation. It does not automatically prove a root cause, but it provides a much stronger starting point than a single green uptime indicator.
The repository includes alert rules covering application availability, latency, server errors, infrastructure pressure, data services, and RabbitMQ queues. Their usefulness depends on the corresponding measurements being available and correctly labelled.
Rule evaluation and notification delivery are separate concerns. The checked-in central stack does not include Alertmanager, so escalation routing and notification configuration remain additional operational work.
Infrastructure and deployment
The deployment model uses a dedicated monitoring VM and a companion Docker Compose stack on each application VM.
Metrics collection is designed to travel over a private overlay network, such as Tailscale or WireGuard. Exporters bind to private interfaces, and application integration guides call for private monitoring endpoints. Public websites remain accessible to users without exposing their internal telemetry.
The central services use persistent Docker volumes. Prometheus defaults to 30 days of metric retention, with that period configurable.
Configuration files define scrape targets, alert rules, and Grafana provisioning. This makes the monitoring setup reviewable and repeatable alongside other infrastructure configuration.
A dedicated monitoring VM also separates monitoring from any one application’s host. It can continue observing other deployments if an application VM fails. The current single-VM central design does not provide high availability for monitoring itself.
What the project provides today
The implemented foundation includes central service definitions, infrastructure exporter configurations, target discovery files, alert rules, Grafana provisioning, and application onboarding guidance.
Some capabilities still require deployment-specific work:
- Dashboards: the provisioning mechanism is present, but the dashboard directory currently describes recommended dashboards rather than shipping a completed dashboard collection.
- Application instrumentation: integration guides explain the required code changes; those changes live in the individual application projects.
- Availability checks: Uptime Kuma must be configured with the endpoints and checks relevant to each application.
- Advanced observability: central log aggregation, distributed tracing, richer alert routing, and SLO reporting are future extensions.
The current project is therefore a metrics and availability foundation, with a defined path toward broader observability.
Key advantages
Consistent visibility across applications. A common collection model reduces the need to learn a different monitoring approach for every product.
Better incident investigation. Application symptoms can be examined alongside queues, databases, containers, and hosts.
Visibility beyond uptime. Latency, error rates, queue growth, and resource pressure can reveal degradation while a service still responds.
Incremental adoption. Teams can start with host and container metrics, then add application instrumentation and dependency-specific collectors.
Control over telemetry. The core metrics pipeline and storage run in infrastructure controlled by the operator, with private collection paths.
A reusable foundation. Standard Prometheus metrics allow different application languages and frameworks to participate in the same monitoring environment.
The practical result is a shared way to understand a growing SaaS ecosystem: whether services respond, how they behave, and where to investigate when their behaviour changes.