Observability-Driven Testing Environment
Enterprise-grade observability testing with OpenTelemetry, Jaeger, Prometheus, Grafana, and Tracetest.
What's Inside
| Tool | Version | Purpose |
|---|---|---|
| OpenTelemetry SDK | Latest | Distributed tracing & metrics instrumentation (Python + JS) |
| Jaeger | 1.57.0 | Trace backend — visualize, search, and analyze distributed traces |
| Prometheus | 2.53.0 | Metrics collection, PromQL queries, SLO validation |
| Grafana | 11.1.0 OSS | Pre-provisioned dashboards for request rate, latency, errors |
| Tracetest | 1.4.2 | Trace-based testing — assert on spans and attributes |
| k6 | 0.52.0 | Load testing with trace context propagation |
| Python | 3.x + venv | Flask demo app, pytest, Locust |
| Node.js | 20 LTS | OpenTelemetry JS SDK, json-server |
| Go | 1.22 | Go-based tooling support |
Quick Start
# Start the observability stack (Jaeger + Prometheus + Grafana)
odt-stack-up
# Start the instrumented demo app
odt-demo-up
# Run trace-based tests
odt-test
# Validate SLOs against Prometheus
odt-slo
# Run k6 load test with trace propagation
odt-load
# Detect latency regressions
odt-regression
Helper Commands
| Command | What it does |
|---|---|
odt-stack-up |
Start Jaeger + Prometheus + Grafana |
odt-stack-down |
Stop the observability stack |
odt-grafana |
Open/restart Grafana dashboards |
odt-demo-up |
Start the instrumented Flask demo app |
odt-test [file] |
Run trace-based tests (pytest) |
odt-slo |
Validate SLOs against Prometheus metrics |
odt-load |
Run k6 load test with trace propagation |
odt-regression |
Detect latency regressions vs baselines |
odt-chaos <mode> |
Inject faults: latency, errors, db-failure, stop |
odt-traces [service] |
Query recent traces from Jaeger |
odt-metrics [query] |
Query Prometheus with PromQL |
odt-help |
Show all available commands |
Accessing Services
Each service is exposed via a subdomain on your workspace URL. After running odt-stack-up, access them from the preview panel or directly:
| Service | Subdomain | Purpose |
|---|---|---|
| Jaeger UI | jaeger.{your-workspace-url} |
Trace visualization and search |
| Prometheus | odt-prometheus.{your-workspace-url} |
Metrics queries and PromQL |
| Grafana | odt-grafana.{your-workspace-url} |
Pre-built dashboards (login: admin/admin or skip) |
| Demo App | odt-demoapp.{your-workspace-url} |
Instrumented Flask API |
Note: The exact URLs are shown in the Preview panel on the right side of your workspace. Click any preview URL to open the service in a new tab.
Exercises
- Instrument Your First App — Add OpenTelemetry tracing, export to Jaeger, view in Grafana
- Trace-Based Testing — Assert on span attributes and trace structure
- SLO Validation — Define SLOs in YAML, validate against Prometheus, confirm in Grafana
- Latency Regression Detection — Define baselines, detect regressions, visualize spikes
- Load Testing with Observability — Run k6 while watching Grafana dashboards live
- Custom Metrics & Alerts — Add Prometheus metrics, write PromQL alert rules
- Distributed Tracing Across Services — Propagate context, validate end-to-end traces
- CI/CD Integration — Run observability tests in pipelines, fail on SLO violations
- Incident Simulation & Root Cause Analysis — Inject chaos (latency/errors/db-failure), diagnose with traces
Project Structure
workspace/
├── app/ # Instrumented demo application
│ └── demo_app.py # Flask + OpenTelemetry + Prometheus metrics
├── tests/ # Trace-based test suites
│ ├── test_traces.py # Jaeger trace assertions
│ ├── test_slo.py # SLO validation against Prometheus
│ └── test_regression.py # Latency regression detection
├── slos/ # SLO definitions
│ └── slo_definitions.yaml
├── load/ # Load test scripts
│ └── k6_traces.js # k6 with trace propagation
├── config/ # Prometheus + OTel config
│ └── prometheus.yml
├── tracetest/ # Tracetest definitions
│ └── trace_test.yaml
├── reports/ # Test outputs
└── README.md
Grafana Dashboard
The workspace comes with a pre-provisioned Observability Overview dashboard (no login required). After running odt-stack-up, open the Grafana preview URL to see:
- Request Rate — Total requests per second over time
- Error Rate — Percentage of failed requests with threshold indicators
- Latency P50 — Median response time in milliseconds
- Latency P95 — 95th percentile response time
- Latency P99 — 99th percentile response time
- Requests by Endpoint — Breakdown of traffic per API route
Demo App Endpoints
The instrumented Flask app exposes these endpoints with full OpenTelemetry tracing:
| Method | Endpoint | Description |
|---|---|---|
| GET | / |
Homepage — lists all available endpoints |
| GET | /users |
List all users (traced DB query) |
| GET | /users/:id |
Get user by ID (traced) |
| POST | /users |
Create a user (traced INSERT) |
| GET | /health |
Health check |
| GET | /metrics |
Prometheus metrics endpoint |
| GET | /slow |
Intentionally slow (for regression testing) |
| POST | /chaos/inject |
Inject chaos fault (mode: latency, errors, db-failure) |
| POST | /chaos/stop |
Stop active chaos injection |
| GET | /chaos/status |
Check current chaos state |
Tips
- Always run
odt-stack-upbeforeodt-demo-up— the app needs Jaeger and Prometheus running - Grafana dashboards update in real-time — open them before running load tests
- Use
odt-tracesto quickly query Jaeger traces from the terminal - SLO definitions are in
slos/slo_definitions.yaml— add your own and runodt-slo - The
/slowendpoint is intentionally slow for regression testing exercises - Use
Ctrl+Shift+Bkeyboard shortcut to start the observability stack - Traces take 2-3 seconds to appear in Jaeger after a request
- All services communicate internally on localhost — the ingress subdomains proxy to the correct ports
Security
- Root access is restricted. Use
sudo apt install <package>for system packages. - pip, npm, python3, docker, apt, and apt-get are whitelisted for sudo access.