

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Difficulty: 7
click for more info
Not enough gems
Cost: 6 gems
1: Metrics
incomplete
2: Prometheus
incomplete
3: System Metrics
incomplete
4: Metrics Exporters
incomplete
5: What to Measure
incomplete
6: Visualizing Metrics
incomplete
7: Service Metrics
incomplete
8: Custom Metrics
incomplete
9: Custom Visualizations
incomplete
10: Status Code Bars
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
Now that we have Linko configured to export the default Prometheus metrics, it's time to set up some custom metrics!
The most basic custom metric that virtually every web app should export is a count of HTTP requests by method, path, and status.
// httpRequestsTotal counts requests by method, path and status.
var httpRequestsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"method", "path", "status"},
)
This snippet defines a package-level Prometheus counter vector with three important attributes:
I defined three labels above: method, path, and status. These labels give us three "dimensions" across which we can track HTTP requests.
Imagine over the course of a minute, your web application receives four HTTP requests, as a user attempts to log in, unsuccessfully at first:
/login 200 OK/login 401 Unauthorized/login 401 Unauthorized/login 200 OKThis increments the http_requests_total counter four times, each with different labels.
| method | path | status | http_requests_total |
|---|---|---|---|
| GET | /login |
200 | 1 |
| POST | /login |
401 | 2 |
| POST | /login |
200 | 1 |
I prefer middleware that handles metric tracking so my "business logic" handlers (the code that does what users care about, like shortening links) don't have to worry about it.
First, define a custom http.ResponseWriter wrapper that captures an HTTP status code when it's written:
type statusRecorder struct {
http.ResponseWriter
status int
}
func (r *statusRecorder) WriteHeader(code int) {
r.status = code
r.ResponseWriter.WriteHeader(code)
}
Then I just write a little middleware function that wraps each request, but also captures the method, path, and status and increments the counter:
func metricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rec := &statusRecorder{
ResponseWriter: w,
status: http.StatusOK,
}
next.ServeHTTP(rec, r)
path := r.URL.Path
method := r.Method
status := strconv.Itoa(rec.status)
httpRequestsTotal.
WithLabelValues(method, path, status).
Inc()
})
}
go run .
Run and submit the CLI tests from the root of the Linko repo.