Introduction: Why Monitoring Is Critical for Go Applications
Go (Golang) has gained popularity in developing high-load microservices, API gateways, and network utilities due to its performance and simplicity. However, even the most stable application can encounter memory leaks, goroutine hangs, or sudden latency spikes. This is where monitoring comes to the rescue — a key practice of Site Reliability Engineering (SRE).
In this article, we will explore how to set up monitoring for Go applications using the Prometheus + Grafana stack, which metrics to collect first, and how to configure alerts to prevent incidents. The material will be useful for both beginner Go developers and experienced engineers looking to improve the observability of their services.
1. Key Metrics of a Go Application
Before setting up monitoring, it is important to understand which metrics are vital for a Go service. They can be divided into three categories:
1.1. Go Runtime Metrics
The Go runtime provides rich information about the application state. Using the runtime package and the standard expvar exporter, you can obtain data on:
- Number of goroutines (
runtime.NumGoroutine()) — a sharp increase indicates a goroutine leak. - Memory usage (
runtime.ReadMemStats()) — monitorAlloc,HeapInuse, andGCStats. - Garbage collection time — if GC takes more than 5% of time, it is a signal for optimization.
- Number of system calls — may indicate blocking.
1.2. Business Metrics
To understand the health of the service, it is necessary to monitor business indicators:
- RPS (Requests Per Second) — number of requests per second.
- Latency (P50, P95, P99) — request processing delays.
- Error rate — percentage of errors (5xx, 4xx).
- Number of active connections (database, external APIs).
1.3. Infrastructure Metrics
Do not forget about system metrics: CPU, memory, disk I/O, network packets. They help distinguish application problems from host problems.
2. Integration with Prometheus: Exporting Metrics
Prometheus is the de facto standard for collecting metrics in the Go world. Let's look at a step-by-step integration.
2.1. Installing the Prometheus Client for Go
Add the dependency to your go.mod:
go get github.com/prometheus/client_golang/prometheusgo get github.com/prometheus/client_golang/prometheus/promhttp2.2. Creating Custom Metrics
Example of creating a request counter and a histogram for response time:
package main
import ( "net/http" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp")
var ( requestCount = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests", }, []string{"method", "endpoint", "status"}, ) requestDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "Duration of HTTP requests in seconds", Buckets: prometheus.DefBuckets, }, []string{"method", "endpoint"}, ))
func init() { prometheus.MustRegister(requestCount) prometheus.MustRegister(requestDuration)}
func metricsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() wrapped := &responseWriter{ResponseWriter: w, statusCode: http.Stat