This repository demonstrates a modern approach to instrumenting Go applications with logs, metrics and traces using OpenTelemetry, showing how to implement a complete observability stack with minimal code changes.
- ✅ Complete working examples of logs, metrics and tracing instrumentation
- ✅ Docker Compose setup for quick deployment
- ✅ Pre-configured Grafana dashboards
- ✅ Request count and latency histogram metrics
- ✅ Distributed tracing with detailed span information
- ✅ Correlation between metrics, traces and logs in a single UI
Modern OpenTelemetry Approach with Complete Observability Stack (Metrics, Traces, Logs)
- Instrumentation: Uses OpenTelemetry SDK for Go (metrics and traces)
- Collection: OpenTelemetry Collector
- Metrics Storage: Grafana Mimir (Prometheus-compatible)
- Trace Storage: Grafana Tempo
- Log Aggregation: Grafana Loki
- Visualization: Grafana dashboards and Explore
Data Flow:
- Metrics: Go App → OTel SDK → OTel Collector → Mimir → Grafana
- Traces: Go App → OTel SDK → OTel Collector → Tempo → Grafana
- Logs: Go App → Zerolog → Promtail → Loki → Grafana
Modern OpenTelemetry Approach with Traces & Metrics
This branch demonstrates the modern approach to observability using the OpenTelemetry standard:
- Instrumentation: Uses OpenTelemetry SDK for Go (metrics and traces)
- Collection: OpenTelemetry Collector
- Metrics Storage: Grafana Mimir (Prometheus-compatible)
- Trace Storage: Grafana Tempo
- Visualization: Grafana dashboards and Explore
Data Flow:
- Metrics: Go App → OTel SDK → OTel Collector → Mimir → Grafana
- Traces: Go App → OTel SDK → OTel Collector → Tempo → Grafana
Traditional Prometheus Approach
This branch demonstrates the classic Prometheus instrumentation approach:
- Instrumentation: Prometheus client library for Go
- Collection: Direct scraping by Prometheus
- Storage: Grafana Mimir
- Visualization: Same Grafana dashboards (for direct comparison)
Data Flow: Go App → Prometheus client → Prometheus → Mimir → Grafana
- 🐳 Docker and Docker Compose
- 🧪 Git
- 🔄 curl (for testing)
-
Clone the repository:
git clone git@github.com:sandeepkv93/go-observability-demo.git cd go-observability-demo
-
Start the stack:
docker-compose up -d
-
Access the Grafana dashboard:
- URL: http://localhost:3000
- Default user/pass: admin/admin
-
Generate some traffic:
./hit-loop.sh
chmod +x hit-loop.sh
./hit-loop.sh 200 0.2
Navigate to the pre-configured dashboard in Grafana to see:
- Request counts
- Request duration percentiles
- Error rates
In Grafana, use the Explore tab and select the Tempo data source to:
- View all traces
- Search by trace ID
- Filter by service, duration, or status
Use Grafana's Explore tab with the Loki data source to:
- View all logs with
{job="go-app"}
- Filter by service with
{service="demo-service"}
- Filter by log level with
{job="go-app", level="error"}
- Search for specific text with
{job="go-app"} |= "error"
This demo features full correlation between metrics, traces, and logs:
- From a metric dashboard, select a time range and click "Explore" to find traces
- From a trace view, click "Logs for this span" to see relevant logs
- From logs, click on a trace ID to jump to the corresponding trace
All components automatically share context:
- Trace IDs are included in logs via OpenTelemetry context propagation
- Service names are consistently used across all telemetry types
- Timestamps are synchronized for temporal correlation
/go-app/metrics
- Metrics instrumentation code/go-app/tracing
- Tracing instrumentation code/go-app/logging
- Logging instrumentation with zerolog/go-app/handlers
- HTTP handlers with observability
/configs
- All configuration files for observability tools/configs/grafana
- Grafana configuration and dashboards/configs/grafana/provisioning
- Datasources and dashboards
/configs/loki
- Loki log aggregation configuration/configs/promtail
- Promtail log collection configuration/configs/mimir
- Mimir metrics configuration/configs/tempo
- Tempo tracing configuration/configs/otel-collector
- OpenTelemetry Collector configuration
docker-compose.yml
- Container orchestrationhit-loop.sh
- Test script for generating traffic
- Request Count: Total number of requests
- Request Duration: Histogram of request durations
- Request Duration Percentiles: p50, p90, p95, and p99 latency
- Request Rate: Requests per second
- Average Latency: Average request duration
- Structured JSON Logs: All logs are in structured JSON format
- Context-Enriched: Logs include trace IDs, span IDs, and service name
- Level-Based Filtering: Support for filtering by log level (info, error, etc.)
🚀 OpenTelemetry Stack with Loki, Promtail, Tempo, Mimir, and Grafana (otel-loki-tempo-mimir-grafana branch)
┌────────────┐ ┌─────────────────┐ ┌──────────────────┐ ┌─────────┐
│ │ │ │ │ │ │ │
│ Go App ├───►│ OTel Collector ├─── │ Grafana Mimir ├───►│ Grafana │
│ (OTel SDK) │ │ │ │ │ │ │
└────────────┘ └─────────────────┘ └──────────────────┘ └─────────┘
┌────────────┐ ┌─────────────────┐ ┌──────────────────┐ ┌─────────┐
│ │ │ │ │ │ │ │
│ Go App ├───►│ OTel Collector ├─── │ Grafana Tempo ├───►│ Grafana │
│ (OTel SDK) │ │ │ │ │ │ │
└────────────┘ └─────────────────┘ └──────────────────┘ └─────────┘
┌────────────┐ ┌─────────────────┐ ┌──────────────────┐ ┌─────────┐
│ │ │ │ │ │ │ │
│ Go App ├───►│ Promtail ├─── │ Grafana Loki ├───►│ Grafana │
│ (OTel SDK) │ │ │ │ │ │ │
└────────────┘ └─────────────────┘ └──────────────────┘ └─────────┘
┌────────────┐ ┌─────────────────┐ ┌──────────────────┐ ┌─────────┐
│ │ │ │ │ │ │ │
│ Go App ├───►│ OTel Collector ├─── │ Grafana Mimir ├───►│ Grafana │
│ (OTel SDK) │ │ │ │ │ │ │
└────────────┘ └─────────────────┘ └──────────────────┘ └─────────┘
┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ ┌─────────┐
│ │ │ │ │ │ │ │
│ Go App │◄───┤ Prometheus ├───►│ Grafana Mimir ├───►│ Grafana │
│(Prom client)│ │ │ │ │ │ │
└─────────────┘ └─────────────┘ └──────────────────┘ └─────────┘
- docker-compose.yml: Docker Compose configuration
- otel-collector-config.yaml: OpenTelemetry Collector configuration
- configs/loki/loki-config.yml: Loki configuration
- configs/promtail/config.yml: Promtail configuration for log collection
- mimir-config.yaml: Mimir configuration
- grafana/provisioning/: Grafana provisioning files
- hit-loop.sh: Script to generate traffic
Use Grafana's Explore feature to explore available telemetry:
- Open Grafana (http://localhost:3000)
- Click on the Explore icon in the left sidebar
- Select a data source (Prometheus for metrics, Tempo for traces, Loki for logs)
- Run queries and filter as needed
To follow a request through traces and logs:
- Find a trace in Tempo
- Click on any span
- Click the "Logs for this span" button to see correlated logs
- Alternatively, search logs with a trace ID:
{job="go-app"} |~ "trace_id=<trace-id>"
Use Grafana's Explore feature to explore all available metrics:
- Open Grafana (http://localhost:3000)
- Click on the Explore icon in the left sidebar
- Try queries like:
{__name__=~".*request.*"}
rate(demo_requests_total[1m])
histogram_quantile(0.95, sum(rate(demo_request_duration_seconds_bucket[1m])) by (le))
Here are some useful queries for analyzing your application:
# Request Rate (per second)
rate(demo_requests_total[1m])
# 95th Percentile Latency
histogram_quantile(0.95, sum(rate(demo_request_duration_seconds_bucket[1m])) by (le))
# Error Rate
rate(demo_request_errors_total[1m])
# Request Rate by Endpoint
sum(rate(demo_requests_total[1m])) by (endpoint)
- OpenTelemetry: Newer standard that provides a unified approach for metrics, traces, and logs
- Prometheus: Well-established standard for metrics with a large ecosystem
- Comparison: Helps you decide which approach fits your needs better
To switch between the two implementations:
# Stop the current stack
docker-compose down
# Switch branch
git checkout prometheus-and-mimir # or otel-mimir-grafana
# Start the stack again
docker-compose up -d
-
OTel Collector Not Starting:
# Check logs docker-compose logs otel-collector # Validate configuration docker run --rm -v $(pwd)/otel-collector-config.yaml:/config.yaml otel/opentelemetry-collector validate --config=/config.yaml
-
Metrics Not Showing in Grafana:
# Check Mimir targets curl http://localhost:9009/api/v1/targets | jq # Verify metrics are being collected curl http://localhost:9009/api/v1/query?query=up
-
Docker Compose Network Issues:
# Recreate network docker-compose down docker network prune -f docker-compose up -d
- Go Application: Simple web service instrumented with OpenTelemetry
- OpenTelemetry Collector: Receives, processes, and exports telemetry data
- Mimir: Stores and queries time-series metrics
- Tempo: Stores and queries distributed traces
- Grafana: Visualizes metrics and traces in a unified UI
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenTelemetry community
- Prometheus community
- Grafana Labs for Mimir and Grafana
Made with ❤️ by Sandeep Vishnu