This is a proof of concept application demonstrating OpenTelemetry metrics collection and visualization using Grafana Alloy, Mimir, and Grafana.
The application consists of:
- Go API Application: A test API server that generates metrics and sends them via OTLP
- Grafana Alloy: Receives OTLP metrics and forwards them to Prometheus remote write
- Cortex Tenant: Multi-tenant proxy for metrics
- Mimir: Metrics storage backend
- Grafana: Metrics visualization dashboard
- Go 1.24.5 or later
- Docker and Docker Compose
- Make (optional, for convenience commands)
go mod downloadStart all the infrastructure services (Alloy, Cortex Tenant, Mimir, and Grafana) using Docker Compose:
docker-compose up -dThis will start:
- Alloy on ports
4317(gRPC),4318(HTTP), and9464(metrics) - Cortex Tenant on port
8085 - Mimir on port
9009 - Grafana on port
3000
Check that all services are up:
docker-compose psYou should see all services in "Up" status.
Build and run the Go application:
cd cmd/api_test
go run .The application will start on port 8088 and automatically send metrics to the OTLP endpoint at http://localhost:4318.
The application exposes a single endpoint:
# Basic request
curl http://localhost:8088/api
# Request with custom status code
curl http://localhost:8088/api?sc=404
# Request with Client-ID header (for multi-tenant testing)
curl -H "Client-ID: 11111" http://localhost:8088/apiThe API will:
- Return a response with a random delay (0-500ms)
- Accept a
scquery parameter to return different HTTP status codes - Accept a
Client-IDheader for tenant identification - Automatically send OpenTelemetry metrics for each request
- Open your browser and navigate to
http://localhost:3000 - Login with:
- Username:
admin - Password:
admin
- Username:
- Configure Mimir as a data source:
- Go to Configuration → Data Sources
- Add a new Prometheus data source
- Set URL to
http://mimir:9009 - Save and test the connection
After making some API requests, you can query metrics in Grafana:
- Navigate to Explore
- Select your Mimir data source
- Query for metrics like:
http_server_request_duration_secondshttp_server_request_total- Custom metrics from your application
The application is configured via environment variables (set in main.go):
OTEL_EXPORTER_OTLP_ENDPOINT: OTLP endpoint (default:http://localhost:4318)OTEL_EXPORTER_OTLP_PROTOCOL: Protocol to use (default:http/protobuf)
Alloy configuration is in config.alloy. It:
- Receives OTLP metrics on ports 4317 (gRPC) and 4318 (HTTP)
- Exports metrics to Prometheus remote write via Cortex Tenant
Mimir configuration is in mimir.yaml. It stores metrics in the local mimir-data directory.
Cortex Tenant configuration is in cortex-tenant.yaml. It handles multi-tenant routing of metrics.
To stop all services:
docker-compose downTo stop and remove all data (including Mimir blocks):
docker-compose down -v- Verify Alloy is running:
docker-compose ps - Check Alloy logs:
docker-compose logs alloy - Verify OTLP endpoint is accessible:
curl http://localhost:4318
- Verify Mimir is running:
docker-compose ps - Check Mimir logs:
docker-compose logs mimir - Verify Grafana data source is configured correctly
- Check Cortex Tenant logs:
docker-compose logs cortex_tenant
If any ports are already in use, modify the port mappings in docker-compose.yml.
.
├── cmd/api_test/ # Go application source
│ ├── main.go # Application entry point
│ ├── router.go # HTTP router setup
│ ├── http.go # HTTP handlers
│ ├── metrics.go # Metrics instrumentation
│ └── container.go # Dependency injection
├── config.alloy # Grafana Alloy configuration
├── cortex-tenant.yaml # Cortex Tenant configuration
├── mimir.yaml # Mimir configuration
├── docker-compose.yml # Infrastructure services
└── mimir-data/ # Mimir storage (created at runtime)
This is a proof of concept project for demonstration purposes.
