If you find this project useful, please consider giving it a ⭐ star on GitHub!
Read the Article: Observing Frontend App with Grafana & Loki (Part 1)
Option 1: Use Grafana Cloud
For a fully managed observability stack, you can use Grafana Cloud instead of running Grafana, Loki, and Alloy locally. See the project setup and instructions in the
feat/faro-grafana-cloud
branch.
A full-stack project featuring a React + TypeScript frontend (built with Vite), containerized with Docker, and integrated with Grafana, Loki, and Alloy for observability and monitoring.
- Frontend: React + TypeScript + Vite
- Monitoring: Grafana dashboards, Loki for logs, Alloy for telemetry collection
- Containerized: All services run via Docker Compose
- Nginx: Serves the frontend and proxies telemetry
This diagram shows how the frontend, Alloy, Loki, and Grafana interact. The React app sends telemetry and logs to Alloy, which forwards them to Loki. Grafana visualizes this data using pre-configured dashboards.
- Docker
- Docker Compose
- (Optional) Node.js and npm for local frontend development
git clone https://github.com/tmohammad78/frontend-monitor.git -b feat/faro-grafana-alloy
cd frontend-monitor
This will build and start the frontend, Grafana, Loki, and Alloy:
docker-compose up --build
- Frontend: http://localhost:5173
- Grafana: http://localhost:3000 (default login:
admin
/admin
) - Alloy UI: http://localhost:12345
You can use the Graph tab in Alloy UI to verify that Alloy is connected and receiving telemetry data.
If you want to develop the frontend locally (with hot reload):
cd contact-app
npm install
npm run dev
Visit http://localhost:5173.
- Lint:
npm run lint
- Build:
npm run build
- Preview Production Build:
npm run preview
- Grafana Dashboards: Pre-configured dashboards for frontend metrics/logs. The dashboards and tables are defined in
infra/grafana/dashboards/
and are automatically loaded when you rundocker-compose up
. - Loki: Log aggregation. Loki is set up as a data source for Grafana.
- Alloy: Telemetry collection and forwarding. You can access the Alloy UI at http://localhost:12345 and use the Graph tab to check connectivity.
- If you do not see the dashboards or tables automatically, you can manually import the
frontend-application.json
file frominfra/grafana/dashboards/
into Grafana. - If Loki is not set as a data source, add it manually in Grafana (URL:
http://loki:3100
).
Grafana provides a rich dashboard UI for visualizing metrics and logs. The dashboards are auto-provisioned from the infra/grafana/dashboards/
folder. You can view user activity, errors, and performance metrics in real time.
All logs from the frontend are collected by Alloy and sent to Loki. In Grafana, you can use the “Explore” tab to query and view logs, filter by severity, and correlate logs with metrics and traces.
contact-app/
— React frontend app (Vite, TypeScript)infra/
— Nginx config, observability configs, Grafana dashboardsdocker-compose.yml
— Orchestrates all services
- Nginx config:
infra/nginx.conf
- Grafana dashboards:
infra/grafana/dashboards/
- Alloy config:
infra/alloy/config.alloy
- The main app (
App.tsx
) is intentionally written with some bad practices to help you observe performance and error monitoring:- Increased LCP (Largest Contentful Paint): The main image is loaded with a 5-second delay and a blocking button is provided to simulate main thread blocking.
- Increased CLS (Cumulative Layout Shift): The image and content appear after a delay, causing layout shifts.
- Error Simulation: The
/error
route throws an error to test error boundaries and logging. There are also simulated soft errors in the code. - API Error Simulation: Use the Tweak extension to mock the API call to return a 500 status code if you want to see error logs in Grafana.
- Routes:
/
— User list (with delayed image and blocking button)/detail/:id
— User detail page/error
— Throws an error and adds it to the DOM for error monitoring
Feel free to contact me at [email protected]. I am always open to feedback, suggestions, and constructive criticism to improve this project!
MIT